Compare commits
17 Commits
main
..
gmap-testing
| Author | SHA1 | Date | |
|---|---|---|---|
| 47b59a5b55 | |||
| b7743a81cb | |||
| 5d95f344dc | |||
| 6c915fd547 | |||
| 1a9c024c92 | |||
| 280bfc25b4 | |||
| 9d475bda31 | |||
| 8ce9f72f4a | |||
| 1189945df0 | |||
| 9d82bf91e3 | |||
| f54d1d3572 | |||
| 7f9db04724 | |||
| 557e25897e | |||
| 634c5d21cd | |||
| 5b81df6507 | |||
| 9b3b53fd3c | |||
| ce91c33272 |
+2
-8
@@ -9,14 +9,8 @@ set(SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
|
||||
)
|
||||
|
||||
if (CONFIG_SOC_COMPATIBLE_NRF52X)
|
||||
target_sources(app PRIVATE src/controller_time_nrf52.c)
|
||||
elseif (CONFIG_SOC_COMPATIBLE_NRF5340_CPUAPP)
|
||||
target_sources(app PRIVATE src/audio_sync_timer_rtc.c)
|
||||
elseif (CONFIG_SOC_SERIES_NRF54LX OR CONFIG_SOC_SERIES_NRF54HX)
|
||||
target_sources(app PRIVATE src/controller_time_nrf54.c)
|
||||
else()
|
||||
MESSAGE(FATAL_ERROR "Unsupported series")
|
||||
if (CONFIG_AUDIO_SYNC_TIMER_USES_RTC)
|
||||
list(APPEND SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/audio_sync_timer_rtc.c)
|
||||
endif()
|
||||
|
||||
target_sources(app PRIVATE ${SRCS})
|
||||
|
||||
@@ -4,7 +4,7 @@ menu "Modules"
|
||||
rsource "Kconfig.defaults"
|
||||
|
||||
config AUDIO_SYNC_TIMER_USES_RTC
|
||||
bool "Enables synchronization between the APP and NET core running SD"
|
||||
bool "Enables syncronization between the APP and NET core running SD"
|
||||
default !BT_LL_ACS_NRF53 && SOC_SERIES_NRF53X
|
||||
select NRFX_RTC0
|
||||
select NRFX_DPPI
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
config NRF_DEFAULT_IPC_RADIO
|
||||
default y
|
||||
|
||||
source "${ZEPHYR_BASE}/share/sysbuild/Kconfig"
|
||||
@@ -15,99 +15,18 @@ It has been tested on the nRF5340 Audio DK, but it should work with any nRF5340
|
||||
- Response: HCI Command Complete Event with status and 4 bytes timestamp in microseconds
|
||||
|
||||
|
||||
|
||||
## nRF58233 Development Kit
|
||||
|
||||
The first Virtual UART (UART1, ...) is Zephyr UART 0
|
||||
The second Virtual UART (UART2, ...) is Zephyr UART 1
|
||||
|
||||
### Pinout
|
||||
|
||||
Signal direction as seen from the nRF52833.
|
||||
|
||||
| PIN | Arduino | MCU | Direction |
|
||||
|----------|---------|-------|-----------|
|
||||
| TX | D0 | P0.05 | out |
|
||||
| RX | D1 | P0.06 | in |
|
||||
| RTS | D7 | P0.07 | out |
|
||||
| CTS | D8 | P0.08 | in |
|
||||
| Time Sync| D10 | P1.01 | out |
|
||||
|
||||
### HCI over UART 0 connected to first Virtual UART in J-Link Probe
|
||||
|
||||
Release build:
|
||||
```sh
|
||||
west build --pristine -b nrf52833dk/nrf52833
|
||||
```
|
||||
Debug build:
|
||||
```sh
|
||||
west build --pristine -b nrf52833dk/nrf52833 -- -DOVERLAY_CONFIG=debug.conf
|
||||
```
|
||||
|
||||
To use UART 0 via Arduino headers, the virtual UART of the J-Link probe needs to be disabled, e.g. with the JLink Configuration Tool.
|
||||
|
||||
|
||||
|
||||
## nRF5340 Development Kit
|
||||
|
||||
The first Virtual UART (UART1, ...) is Zephyr UART 1
|
||||
The second Virtual UART (UART2, ...) is Zephyr UART 0
|
||||
|
||||
### Pinout
|
||||
|
||||
Signal direction as seen from the nRF5340.
|
||||
|
||||
| PIN | Arduino | MCU | Direction |
|
||||
|----------|---------|-------|-----------|
|
||||
| TX | D0 | P1.00 | out |
|
||||
| RX | D1 | P1.01 | in |
|
||||
| RTS | D7 | P1.11 | out |
|
||||
| CTS | D8 | P1.10 | in |
|
||||
| Time Sync| D10 | P1.06 | out |
|
||||
|
||||
### HCI over USB CDC
|
||||
|
||||
```sh
|
||||
west build --pristine -b nrf5340dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=usb.overlay -DOVERLAY_CONFIG=overlay-usb.conf
|
||||
west build -b nrf5340dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=usb.overlay -DOVERLAY_CONFIG=overlay-usb.conf
|
||||
```
|
||||
|
||||
|
||||
### HCI over UART 0 connected to second Virtual UART in J-Link Probe
|
||||
```sh
|
||||
west build --pristine -b nrf5340dk/nrf5340/cpuapp
|
||||
```
|
||||
|
||||
- HCI over second Virtual port / UART 0
|
||||
- Boot banner on Arduino Header UART (P1.01) / UART 1
|
||||
|
||||
|
||||
### HCI over UART 1 connected to first Virtual UART in J-Link Probe as well as Arduino Headers
|
||||
```sh
|
||||
west build --pristine -b nrf5340dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=uart1.overlay
|
||||
```
|
||||
|
||||
- No Boot Banner on Arduino Header UART
|
||||
|
||||
_HCI over UART and timesync not tested._
|
||||
|
||||
|
||||
## nRF5340 Audio DK
|
||||
|
||||
The first UART (UART1, P1.04, P1.05) is only available via test points (TP60, TP61, ...)
|
||||
The second UART (UART2, P1.08, P1.09) is connected to the Arduino headers.
|
||||
|
||||
### Pinout
|
||||
|
||||
Signal direction as seen from the nRF5340.
|
||||
|
||||
| PIN | Arduino | MCU | Direction |
|
||||
|----------|---------|-------|-----------|
|
||||
| TX | D0 | P1.09 | out |
|
||||
| RX | D1 | P1.08 | in |
|
||||
| RTS | D7 | P1.11 | out |
|
||||
| CTS | D8 | P1.10 | in |
|
||||
| Time Sync| D10 | P1.01 | out |
|
||||
|
||||
|
||||
### HCI over USB CDC
|
||||
|
||||
```sh
|
||||
@@ -117,7 +36,7 @@ west build --pristine -b nrf5340_audio_dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_
|
||||
### HCI over UART 0 connected to Virtual UART in J-Link Probe
|
||||
|
||||
```sh
|
||||
west build --pristine -b nrf5340_audio_dk/nrf5340/cpuapp
|
||||
west build --pristine -b nrf5340_audio_dk_nrf5340_cpuapp
|
||||
```
|
||||
|
||||
### HCI over UART 1 connected to Virtual UART in J-Link Probe as well as Arduino Headers
|
||||
@@ -134,38 +53,14 @@ west build --pristine -b nrf5340_audio_dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_
|
||||
|
||||
To use UART 1 via Arduino headers, the virtual UART of the J-Link probe needs to be disabled, e.g. with the JLink Configuration Tool.
|
||||
|
||||
### UART 1 + Time Sync Pinout
|
||||
|
||||
Signal direction as seen from the nRF5340.
|
||||
|
||||
## nRF54L15
|
||||
|
||||
### HCI over UART 0 connected to second Virtual UART in J-Link Probe
|
||||
|
||||
Release build:
|
||||
```sh
|
||||
west build -d nrf54l15-iso --pristine -b nrf54l15dk/nrf54l15/cpuapp
|
||||
```
|
||||
Debug build:
|
||||
```sh
|
||||
west build -d nrf54l15-iso --pristine -b nrf54l15dk/nrf54l15/cpuapp -- -DOVERLAY_CONFIG=debug.conf
|
||||
```
|
||||
|
||||
To use UART 0 via Arduino headers, the virtual UART of the J-Link probe needs to be disabled, e.g. with the JLink Configuration Tool.
|
||||
|
||||
### Pinout
|
||||
|
||||
Signal direction as seen from the nRF54L15.
|
||||
|
||||
| PIN | MCU | Direction |
|
||||
|----------|-------|-----------|
|
||||
| TX | P0.00 | out |
|
||||
| RX | P0.01 | in |
|
||||
| RTS | P0.02 | out |
|
||||
| CTS | P0.03 | in |
|
||||
| Time Sync| P1.11 | out |
|
||||
|
||||
|
||||
## Maintainer Notes
|
||||
- nRF5340 use Controller configuration in `sybuild/ipc_radio/prj.conf`, while others, e.g. nRF54L15, use configuration from `prj.conf`. Please update both at the same time.
|
||||
- We can detect nRF5340 SoC in CMake with `if(CONFIG_SOC STREQUAL "nrf5340")` after find_package zephyr.
|
||||
|
||||
|
||||
| PIN | Arduino | nrf | Direction |
|
||||
|----------|---------|-------|-----------|
|
||||
| TX | D0 | P1.09 | out |
|
||||
| RX | D1 | P1.08 | in |
|
||||
| RTS | D7 | P1.11 | out |
|
||||
| CTS | D8 | P1.10 | in |
|
||||
| Timesync | D10 | P1.01 | out |
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
CONFIG_NRFX_TIMER1=y
|
||||
CONFIG_NRFX_RTC2=y
|
||||
CONFIG_NRFX_PPI=y
|
||||
@@ -4,17 +4,6 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/ {
|
||||
host_interface {
|
||||
compatible = "gpio-outputs";
|
||||
status = "okay";
|
||||
timesync: pin_0 {
|
||||
gpios = <&gpio1 01 GPIO_ACTIVE_HIGH>;
|
||||
label = "Controller to host timesync pin";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
compatible = "nordic,nrf-uarte";
|
||||
current-speed = <1000000>;
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2024 Nordic Semiconductor
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
CONFIG_NRFX_TIMER1=y
|
||||
CONFIG_NRFX_RTC2=y
|
||||
CONFIG_NRFX_PPI=y
|
||||
@@ -6,7 +6,11 @@
|
||||
gpios = <&arduino_header 10 GPIO_ACTIVE_HIGH>;
|
||||
label = "Controller to host timesync pin";
|
||||
};
|
||||
};
|
||||
alternate_toggle: pin_1 {
|
||||
gpios = <&arduino_header 11 GPIO_ACTIVE_HIGH>;
|
||||
label = "alternate toggle pin";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/ {
|
||||
host_interface {
|
||||
compatible = "gpio-outputs";
|
||||
status = "okay";
|
||||
timesync: pin_0 {
|
||||
gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
|
||||
label = "Controller to host timesync pin";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&uart20 {
|
||||
compatible = "nordic,nrf-uarte";
|
||||
current-speed = <1000000>;
|
||||
status = "okay";
|
||||
hw-flow-control;
|
||||
};
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
&uart20 {
|
||||
compatible = "nordic,nrf-uarte";
|
||||
current-speed = <1000000>;
|
||||
status = "okay";
|
||||
hw-flow-control;
|
||||
};
|
||||
|
||||
&radio {
|
||||
status = "okay";
|
||||
/* This is an example number of antennas that may be available
|
||||
* on antenna matrix board.
|
||||
*/
|
||||
dfe-antenna-num = <10>;
|
||||
/* This is an example switch pattern that will be used to set an
|
||||
* antenna for Tx PDU (period before start of Tx CTE).
|
||||
*/
|
||||
dfe-pdu-antenna = <0x0>;
|
||||
|
||||
/* These are example GPIO pin numbers that are provided to
|
||||
* Radio peripheral. The pins will be acquired by Radio to
|
||||
* drive antenna switching when AoD is enabled.
|
||||
*/
|
||||
dfegpio0-gpios = <&gpio1 4 0>;
|
||||
dfegpio1-gpios = <&gpio1 5 0>;
|
||||
dfegpio2-gpios = <&gpio1 6 0>;
|
||||
dfegpio3-gpios = <&gpio1 7 0>;
|
||||
};
|
||||
@@ -21,7 +21,7 @@ CONFIG_BT_CTLR_ADV_ISO_SET=2
|
||||
CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=3
|
||||
CONFIG_BT_CTLR_SYNC_PERIODIC_ADV_LIST_SIZE=1
|
||||
|
||||
# Support six links as a central, or one link as a peripheral
|
||||
# Support two links as a central, or one link as a peripheral
|
||||
CONFIG_BT_MAX_CONN=8
|
||||
CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT=2
|
||||
|
||||
|
||||
@@ -14,38 +14,25 @@ CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255
|
||||
CONFIG_BT_CTLR_ASSERT_HANDLER=y
|
||||
CONFIG_BT_MAX_CONN=16
|
||||
CONFIG_BT_TINYCRYPT_ECC=n
|
||||
|
||||
# Setup ISO Buffer
|
||||
CONFIG_BT_ISO_TX_BUF_COUNT=10
|
||||
CONFIG_BT_ISO_TX_MTU=251
|
||||
CONFIG_BT_ISO_RX_BUF_COUNT=10
|
||||
CONFIG_BT_ISO_RX_MTU=251
|
||||
CONFIG_BT_CTLR_DTM_HCI=y
|
||||
|
||||
# Enable ISO support
|
||||
CONFIG_BT_ISO_PERIPHERAL=y
|
||||
CONFIG_BT_ISO_CENTRAL=y
|
||||
CONFIG_BT_ISO_BROADCASTER=y
|
||||
CONFIG_BT_ISO_SYNC_RECEIVER=y
|
||||
CONFIG_BT_EXT_ADV=y
|
||||
CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER=y
|
||||
CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER=y
|
||||
CONFIG_BT_ISO_TX_BUF_COUNT=10
|
||||
CONFIG_BT_ISO_TX_MTU=251
|
||||
CONFIG_BT_ISO_RX_BUF_COUNT=10
|
||||
CONFIG_BT_ISO_RX_MTU=251
|
||||
|
||||
# Configure Controller
|
||||
CONFIG_BT_CTLR_CONN_ISO_GROUPS=1
|
||||
CONFIG_BT_CTLR_CONN_ISO_STREAMS=3
|
||||
CONFIG_BT_CTLR_SYNC_ISO_STREAM_COUNT=2
|
||||
CONFIG_BT_CTLR_ADV_EXT=y
|
||||
CONFIG_BT_CTLR_ADV_SET=2
|
||||
CONFIG_BT_CTLR_ADV_ISO_SET=2
|
||||
CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=3
|
||||
CONFIG_BT_CTLR_SYNC_PERIODIC_ADV_LIST_SIZE=1
|
||||
# setup rpmsg/Bluetooth buffer
|
||||
CONFIG_BT_BUF_EVT_RX_COUNT=16
|
||||
CONFIG_BT_BUF_EVT_RX_SIZE=255
|
||||
CONFIG_BT_BUF_ACL_RX_SIZE=255
|
||||
CONFIG_BT_BUF_ACL_TX_SIZE=251
|
||||
CONFIG_BT_BUF_CMD_TX_SIZE=255
|
||||
|
||||
# Support six links as a central, or one link as a peripheral
|
||||
CONFIG_BT_MAX_CONN=8
|
||||
CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT=2
|
||||
|
||||
# Allow using more than default advertising event length
|
||||
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=251
|
||||
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512
|
||||
|
||||
# Workaround: Unable to allocate command buffer when using K_NO_WAIT since
|
||||
# Host number of completed commands does not follow normal flow control.
|
||||
@@ -54,3 +41,4 @@ CONFIG_BT_BUF_CMD_TX_COUNT=10
|
||||
# for the timesync command
|
||||
CONFIG_BT_HCI_RAW_CMD_EXT=y
|
||||
|
||||
CONFIG_NRFX_TIMER2=y
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
// BK: based on / taken from ncs/nrf/samples/bluetooth/conn_time_sync/src/controller_time_sync.h
|
||||
|
||||
#ifndef CONTROLLER_TIME_SYNC_H__
|
||||
#define CONTROLLER_TIME_SYNC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
/** @brief Obtain the current Bluetooth controller time.
|
||||
*
|
||||
* The timestamps are based upon this clock.
|
||||
*
|
||||
* @return The current controller time.
|
||||
*/
|
||||
uint64_t controller_time_us_get(void);
|
||||
|
||||
/** @brief Set the controller to trigger a PPI event at the given timestamp.
|
||||
*
|
||||
* @param timestamp_us The timestamp where it will trigger.
|
||||
*/
|
||||
void controller_time_trigger_set(uint64_t timestamp_us);
|
||||
|
||||
/** @brief Get the address of the event that will trigger.
|
||||
*
|
||||
* @return The address of the event that will trigger.
|
||||
*/
|
||||
uint32_t controller_time_trigger_event_addr_get(void);
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@@ -1,292 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/** This file implements controller time management for 52 Series devices
|
||||
*
|
||||
* As the controller clock is not directly accessible, the controller
|
||||
* time is obtained using a mirrored RTC peripheral.
|
||||
* To achieve microsecond accurate toggling, a timer peripheral is also used.
|
||||
*/
|
||||
|
||||
// BK: taken from ncs/nrf/samples/bluetooth/conn_time_sync/src/controller_time_nrf52.c
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/barrier.h>
|
||||
#include <mpsl_clock.h>
|
||||
#include <nrfx_rtc.h>
|
||||
#include <nrfx_timer.h>
|
||||
#include <helpers/nrfx_gppi.h>
|
||||
#include <hal/nrf_egu.h>
|
||||
#include <soc.h>
|
||||
#include "controller_time.h"
|
||||
|
||||
static const nrfx_rtc_t app_rtc_instance = NRFX_RTC_INSTANCE(2);
|
||||
static const nrfx_timer_t app_timer_instance = NRFX_TIMER_INSTANCE(1);
|
||||
|
||||
static uint8_t ppi_chan_on_rtc_match;
|
||||
static volatile uint32_t num_rtc_overflows;
|
||||
|
||||
static uint32_t offset_ticks_and_controller_to_app_rtc;
|
||||
|
||||
static void rtc_isr_handler(nrfx_rtc_int_type_t int_type)
|
||||
{
|
||||
if (int_type == NRFX_RTC_INT_OVERFLOW) {
|
||||
num_rtc_overflows++;
|
||||
}
|
||||
}
|
||||
|
||||
static void unused_timer_isr_handler(nrf_timer_event_t event_type, void *ctx)
|
||||
{
|
||||
ARG_UNUSED(event_type);
|
||||
ARG_UNUSED(ctx);
|
||||
}
|
||||
|
||||
static int32_t rtc_diff_get(void)
|
||||
{
|
||||
uint32_t controller_ticks = nrf_rtc_counter_get(NRF_RTC0);
|
||||
uint32_t app_ticks = nrf_rtc_counter_get(app_rtc_instance.p_reg);
|
||||
|
||||
return controller_ticks - app_ticks;
|
||||
}
|
||||
|
||||
static int rtc_config(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
const nrfx_rtc_config_t rtc_cfg = NRFX_RTC_DEFAULT_CONFIG;
|
||||
|
||||
ret = nrfx_rtc_init(&app_rtc_instance, &rtc_cfg, rtc_isr_handler);
|
||||
if (ret != NRFX_SUCCESS) {
|
||||
printk("Failed initializing RTC (ret: %d)\n", ret - NRFX_ERROR_BASE_NUM);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#ifndef BT_CTLR_SDC_BSIM_BUILD
|
||||
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_RTC_INST_GET(2)), IRQ_PRIO_LOWEST,
|
||||
NRFX_RTC_INST_HANDLER_GET(2), NULL, 0);
|
||||
#else
|
||||
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_RTC_INST_GET(2)), 0,
|
||||
(void *)NRFX_RTC_INST_HANDLER_GET(2), NULL, 0);
|
||||
#endif
|
||||
|
||||
nrfx_rtc_overflow_enable(&app_rtc_instance, true);
|
||||
nrfx_rtc_tick_enable(&app_rtc_instance, false);
|
||||
nrfx_rtc_enable(&app_rtc_instance);
|
||||
|
||||
/* To obtain the controller timestamp without modifying the state of RTC0,
|
||||
* we find the offset between RTC0 and our mirrored RTC.
|
||||
* We achieve this by reading out the counter value of both of them.
|
||||
* When the diff between those two have been equal twice, we know the
|
||||
* time difference in ticks.
|
||||
*/
|
||||
|
||||
uint32_t sync_attempts = 10;
|
||||
|
||||
while (sync_attempts > 0) {
|
||||
sync_attempts--;
|
||||
|
||||
int32_t diff_measurement_1 = rtc_diff_get();
|
||||
|
||||
/* We need to wait half an RTC tick to ensure we are not measuring
|
||||
* the diff between the two RTCs at the point in time where their
|
||||
* values are transitioning.
|
||||
*/
|
||||
k_busy_wait(15);
|
||||
|
||||
int32_t diff_measurement_2 = rtc_diff_get();
|
||||
|
||||
if (diff_measurement_1 == diff_measurement_2) {
|
||||
offset_ticks_and_controller_to_app_rtc = diff_measurement_1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
printk("Controller time sync failure\n");
|
||||
offset_ticks_and_controller_to_app_rtc = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int timer_config(void)
|
||||
{
|
||||
int ret;
|
||||
uint8_t ppi_chan_timer_clear_on_rtc_tick;
|
||||
const nrfx_timer_config_t timer_cfg = {
|
||||
.frequency = NRFX_MHZ_TO_HZ(1UL),
|
||||
.mode = NRF_TIMER_MODE_TIMER,
|
||||
.bit_width = NRF_TIMER_BIT_WIDTH_8,
|
||||
.interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY,
|
||||
.p_context = NULL};
|
||||
|
||||
ret = nrfx_timer_init(&app_timer_instance, &timer_cfg, unused_timer_isr_handler);
|
||||
if (ret != NRFX_SUCCESS) {
|
||||
printk("Failed initializing timer (ret: %d)\n", ret - NRFX_ERROR_BASE_NUM);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Clear the TIMER every RTC tick. */
|
||||
if (nrfx_gppi_channel_alloc(&ppi_chan_timer_clear_on_rtc_tick) != NRFX_SUCCESS) {
|
||||
printk("Failed allocating for clearing TIMER on RTC TICK\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nrfx_gppi_channel_endpoints_setup(ppi_chan_timer_clear_on_rtc_tick,
|
||||
nrfx_rtc_event_address_get(&app_rtc_instance,
|
||||
NRF_RTC_EVENT_TICK),
|
||||
nrfx_timer_task_address_get(&app_timer_instance,
|
||||
NRF_TIMER_TASK_CLEAR));
|
||||
|
||||
nrfx_gppi_channels_enable(BIT(ppi_chan_timer_clear_on_rtc_tick));
|
||||
|
||||
nrfx_timer_enable(&app_timer_instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Configure the TIMER and RTC in such a way that microsecond accurate timing can be achieved.
|
||||
*
|
||||
* To get microsecond accurate toggling, we need to combine both the RTC and TIMER peripheral.
|
||||
* That is, both a RTC CC value and TIMER CC value needs to be set.
|
||||
* We should only trigger an EGU task when the TIMER CC value matches after the
|
||||
* RTC CC value matched.
|
||||
* This is achieved using a PPI group. The group is enabled when the RTC CC matches and disabled
|
||||
* again then the TIMER CC matches.
|
||||
*/
|
||||
int config_egu_trigger_on_rtc_and_timer_match(void)
|
||||
{
|
||||
uint8_t ppi_chan_on_timer_match;
|
||||
|
||||
if (nrfx_gppi_channel_alloc(&ppi_chan_on_rtc_match) != NRFX_SUCCESS) {
|
||||
printk("Failed allocating for RTC match\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (nrfx_gppi_channel_alloc(&ppi_chan_on_timer_match) != NRFX_SUCCESS) {
|
||||
printk("Failed allocating for TIMER match\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nrfx_gppi_group_clear(NRFX_GPPI_CHANNEL_GROUP0);
|
||||
nrfx_gppi_group_disable(NRFX_GPPI_CHANNEL_GROUP0);
|
||||
nrfx_gppi_channels_include_in_group(
|
||||
BIT(ppi_chan_on_timer_match) | BIT(ppi_chan_on_rtc_match),
|
||||
NRFX_GPPI_CHANNEL_GROUP0);
|
||||
|
||||
nrfx_gppi_channel_endpoints_setup(ppi_chan_on_rtc_match,
|
||||
nrfx_rtc_event_address_get(&app_rtc_instance,
|
||||
NRF_RTC_EVENT_COMPARE_0),
|
||||
nrfx_gppi_task_address_get(NRFX_GPPI_TASK_CHG0_EN));
|
||||
|
||||
nrfx_gppi_channel_endpoints_setup(ppi_chan_on_timer_match,
|
||||
nrfx_timer_event_address_get(&app_timer_instance,
|
||||
NRF_TIMER_EVENT_COMPARE0),
|
||||
nrf_egu_task_address_get(NRF_EGU0,
|
||||
NRF_EGU_TASK_TRIGGER0));
|
||||
nrfx_gppi_fork_endpoint_setup(ppi_chan_on_timer_match,
|
||||
nrfx_gppi_task_address_get(NRFX_GPPI_TASK_CHG0_DIS));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int controller_time_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rtc_config();
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = timer_config();
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return config_egu_trigger_on_rtc_and_timer_match();
|
||||
}
|
||||
|
||||
static uint64_t rtc_ticks_to_us(uint32_t rtc_ticks)
|
||||
{
|
||||
const uint64_t rtc_ticks_in_femto_units = 30517578125UL;
|
||||
|
||||
return (rtc_ticks * rtc_ticks_in_femto_units) / 1000000000UL;
|
||||
}
|
||||
|
||||
static uint32_t us_to_rtc_ticks(uint32_t timestamp_us)
|
||||
{
|
||||
const uint64_t rtc_ticks_in_femto_units = 30517578125UL;
|
||||
|
||||
return ((uint64_t)(timestamp_us) * 1000000000UL) / rtc_ticks_in_femto_units;
|
||||
}
|
||||
|
||||
uint64_t controller_time_us_get(void)
|
||||
{
|
||||
const uint64_t rtc_overflow_time_us = 512000000UL;
|
||||
|
||||
/* On the 52 series the RTC has to task to capture the current RTC value.
|
||||
* Therefore we cannot capture the TIMER and RTC value simultaneously.
|
||||
* Therefore we only use the RTC to read out the current time here.
|
||||
* This will result in an error of maximum one RTC tick.
|
||||
*/
|
||||
|
||||
uint32_t captured_rtc_overflows;
|
||||
uint32_t captured_rtc_ticks;
|
||||
|
||||
while (true) {
|
||||
captured_rtc_overflows = num_rtc_overflows;
|
||||
|
||||
/* Read out RTC ticks after reading number of overflows. */
|
||||
barrier_isync_fence_full();
|
||||
|
||||
captured_rtc_ticks = nrf_rtc_counter_get(app_rtc_instance.p_reg);
|
||||
|
||||
/* Read out number of overflows after reading number of RTC ticks */
|
||||
barrier_isync_fence_full();
|
||||
|
||||
if (captured_rtc_overflows == num_rtc_overflows) {
|
||||
/* There were no new overflows after reading ticks.
|
||||
* That is, we can use the captured value.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rtc_ticks_to_us(captured_rtc_ticks) +
|
||||
(captured_rtc_overflows * rtc_overflow_time_us) +
|
||||
rtc_ticks_to_us(offset_ticks_and_controller_to_app_rtc);
|
||||
}
|
||||
|
||||
void controller_time_trigger_set(uint64_t timestamp_us)
|
||||
{
|
||||
uint64_t timestamp_without_rtc_offset =
|
||||
timestamp_us - rtc_ticks_to_us(offset_ticks_and_controller_to_app_rtc);
|
||||
|
||||
uint32_t num_overflows = timestamp_without_rtc_offset / 512000000UL;
|
||||
uint64_t overflow_time_us = num_overflows * 512000000UL;
|
||||
|
||||
uint32_t rtc_remainder_time_us = timestamp_without_rtc_offset - overflow_time_us;
|
||||
uint32_t rtc_val = us_to_rtc_ticks(rtc_remainder_time_us);
|
||||
uint8_t timer_val = timestamp_without_rtc_offset - rtc_ticks_to_us(rtc_val);
|
||||
|
||||
/* Ensure the timer value lies between 1 and 30 so that it will
|
||||
* always be between two RTC ticks.
|
||||
*/
|
||||
timer_val = MAX(timer_val, 1);
|
||||
timer_val = MIN(timer_val, 30);
|
||||
|
||||
if (nrfx_rtc_cc_set(&app_rtc_instance, 0, rtc_val, false) != NRFX_SUCCESS) {
|
||||
printk("Failed setting trigger\n");
|
||||
}
|
||||
|
||||
nrfx_timer_compare(&app_timer_instance, 0, timer_val, false);
|
||||
nrfx_gppi_channels_enable(BIT(ppi_chan_on_rtc_match));
|
||||
}
|
||||
|
||||
uint32_t controller_time_trigger_event_addr_get(void)
|
||||
{
|
||||
return nrf_egu_event_address_get(NRF_EGU0, NRF_EGU_EVENT_TRIGGERED0);
|
||||
}
|
||||
|
||||
SYS_INIT(controller_time_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
||||
@@ -1,270 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/** This file implements controller time management for 53 Series devices
|
||||
*
|
||||
* As the controller clock is not directly accessible, the controller
|
||||
* time is obtained using a mirrored RTC peripheral.
|
||||
* The RTC is started upon starting the controller clock on the network core.
|
||||
* To achieve microsecond accurate toggling, a timer peripheral is also used.
|
||||
*/
|
||||
|
||||
// BK: taken from ncs/nrf/samples/bluetooth/conn_time_sync/src/controller_time_nrf53_app.c
|
||||
// - we already have a similar code in audio_sync_timer_rtc.c from nrf5340_audio
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/init.h>
|
||||
#include <zephyr/sys/barrier.h>
|
||||
#include <helpers/nrfx_gppi.h>
|
||||
#include <nrfx_rtc.h>
|
||||
#include <nrfx_timer.h>
|
||||
#include <hal/nrf_ipc.h>
|
||||
#include <hal/nrf_egu.h>
|
||||
#include "conn_time_sync.h"
|
||||
|
||||
static const nrfx_rtc_t app_rtc_instance = NRFX_RTC_INSTANCE(0);
|
||||
static const nrfx_timer_t app_timer_instance = NRFX_TIMER_INSTANCE(0);
|
||||
|
||||
static uint8_t ppi_chan_on_rtc_match;
|
||||
static volatile uint32_t num_rtc_overflows;
|
||||
|
||||
static void rtc_isr_handler(nrfx_rtc_int_type_t int_type)
|
||||
{
|
||||
if (int_type == NRFX_RTC_INT_OVERFLOW) {
|
||||
num_rtc_overflows++;
|
||||
}
|
||||
}
|
||||
|
||||
static void unused_timer_isr_handler(nrf_timer_event_t event_type, void *ctx)
|
||||
{
|
||||
ARG_UNUSED(event_type);
|
||||
ARG_UNUSED(ctx);
|
||||
}
|
||||
|
||||
static int rtc_config(void)
|
||||
{
|
||||
int ret;
|
||||
uint8_t dppi_channel_rtc_start;
|
||||
const nrfx_rtc_config_t rtc_cfg = NRFX_RTC_DEFAULT_CONFIG;
|
||||
|
||||
ret = nrfx_rtc_init(&app_rtc_instance, &rtc_cfg, rtc_isr_handler);
|
||||
if (ret != NRFX_SUCCESS) {
|
||||
printk("Failed initializing RTC (ret: %d)\n", ret - NRFX_ERROR_BASE_NUM);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#ifndef BT_CTLR_SDC_BSIM_BUILD
|
||||
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_RTC_INST_GET(0)), IRQ_PRIO_LOWEST,
|
||||
NRFX_RTC_INST_HANDLER_GET(0), NULL, 0);
|
||||
#else
|
||||
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_RTC_INST_GET(0)), 0,
|
||||
(void *)NRFX_RTC_INST_HANDLER_GET(0), NULL, 0);
|
||||
#endif
|
||||
|
||||
nrfx_rtc_overflow_enable(&app_rtc_instance, true);
|
||||
nrfx_rtc_tick_enable(&app_rtc_instance, false);
|
||||
nrfx_rtc_enable(&app_rtc_instance);
|
||||
|
||||
|
||||
/* The application core RTC is started synchronously with the controller
|
||||
* RTC using PPI over IPC.
|
||||
*/
|
||||
ret = nrfx_gppi_channel_alloc(&dppi_channel_rtc_start);
|
||||
if (ret != NRFX_SUCCESS) {
|
||||
printk("nrfx DPPI channel alloc error for starting RTC: %d", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
nrf_ipc_receive_config_set(NRF_IPC, 4, NRF_IPC_CHANNEL_4);
|
||||
|
||||
nrfx_gppi_channel_endpoints_setup(dppi_channel_rtc_start,
|
||||
nrfx_rtc_task_address_get(&app_rtc_instance,
|
||||
NRF_RTC_TASK_CLEAR),
|
||||
nrf_ipc_event_address_get(NRF_IPC,
|
||||
NRF_IPC_EVENT_RECEIVE_4));
|
||||
|
||||
nrfx_gppi_channels_enable(BIT(dppi_channel_rtc_start));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int timer_config(void)
|
||||
{
|
||||
int ret;
|
||||
uint8_t ppi_chan_timer_clear_on_rtc_tick;
|
||||
const nrfx_timer_config_t timer_cfg = {
|
||||
.frequency = NRFX_MHZ_TO_HZ(1UL),
|
||||
.mode = NRF_TIMER_MODE_TIMER,
|
||||
.bit_width = NRF_TIMER_BIT_WIDTH_8,
|
||||
.interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY,
|
||||
.p_context = NULL};
|
||||
|
||||
ret = nrfx_timer_init(&app_timer_instance, &timer_cfg, unused_timer_isr_handler);
|
||||
if (ret != NRFX_SUCCESS) {
|
||||
printk("Failed initializing timer (ret: %d)\n", ret - NRFX_ERROR_BASE_NUM);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Clear the TIMER every RTC tick. */
|
||||
if (nrfx_gppi_channel_alloc(&ppi_chan_timer_clear_on_rtc_tick) != NRFX_SUCCESS) {
|
||||
printk("Failed allocating for clearing TIMER on RTC TICK\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nrfx_gppi_channel_endpoints_setup(ppi_chan_timer_clear_on_rtc_tick,
|
||||
nrfx_rtc_event_address_get(&app_rtc_instance,
|
||||
NRF_RTC_EVENT_TICK),
|
||||
nrfx_timer_task_address_get(&app_timer_instance,
|
||||
NRF_TIMER_TASK_CLEAR));
|
||||
|
||||
nrfx_gppi_channels_enable(BIT(ppi_chan_timer_clear_on_rtc_tick));
|
||||
|
||||
nrfx_timer_enable(&app_timer_instance);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Configure the TIMER and RTC in such a way that microsecond accurate timing can be achieved.
|
||||
*
|
||||
* To get microsecond accurate toggling, we need to combine both the RTC and TIMER peripheral.
|
||||
* That is, both a RTC CC value and TIMER CC value needs to be set.
|
||||
* We should only trigger an EGU task when the TIMER CC value
|
||||
* matches after the RTC CC value matched.
|
||||
* This is achieved using a PPI group. The group is enabled when the RTC CC matches and disabled
|
||||
* again then the TIMER CC matches.
|
||||
*/
|
||||
int config_egu_trigger_on_rtc_and_timer_match(void)
|
||||
{
|
||||
uint8_t ppi_chan_on_timer_match;
|
||||
|
||||
if (nrfx_gppi_channel_alloc(&ppi_chan_on_rtc_match) != NRFX_SUCCESS) {
|
||||
printk("Failed allocating for RTC match\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (nrfx_gppi_channel_alloc(&ppi_chan_on_timer_match) != NRFX_SUCCESS) {
|
||||
printk("Failed allocating for TIMER match\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
nrfx_gppi_group_clear(NRFX_GPPI_CHANNEL_GROUP0);
|
||||
nrfx_gppi_group_disable(NRFX_GPPI_CHANNEL_GROUP0);
|
||||
nrfx_gppi_channels_include_in_group(
|
||||
BIT(ppi_chan_on_timer_match) | BIT(ppi_chan_on_rtc_match),
|
||||
NRFX_GPPI_CHANNEL_GROUP0);
|
||||
|
||||
nrfx_gppi_channel_endpoints_setup(ppi_chan_on_rtc_match,
|
||||
nrfx_rtc_event_address_get(&app_rtc_instance,
|
||||
NRF_RTC_EVENT_COMPARE_0),
|
||||
nrfx_gppi_task_address_get(NRFX_GPPI_TASK_CHG0_EN));
|
||||
nrfx_gppi_channel_endpoints_setup(ppi_chan_on_timer_match,
|
||||
nrfx_timer_event_address_get(&app_timer_instance,
|
||||
NRF_TIMER_EVENT_COMPARE0),
|
||||
nrfx_gppi_task_address_get(NRFX_GPPI_TASK_CHG0_DIS));
|
||||
nrfx_gppi_fork_endpoint_setup(ppi_chan_on_timer_match,
|
||||
nrf_egu_task_address_get(NRF_EGU0, NRF_EGU_TASK_TRIGGER0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int controller_time_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = rtc_config();
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = timer_config();
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return config_egu_trigger_on_rtc_and_timer_match();
|
||||
}
|
||||
|
||||
static uint64_t rtc_ticks_to_us(uint32_t rtc_ticks)
|
||||
{
|
||||
const uint64_t rtc_ticks_in_femto_units = 30517578125UL;
|
||||
|
||||
return (rtc_ticks * rtc_ticks_in_femto_units) / 1000000000UL;
|
||||
}
|
||||
|
||||
static uint32_t us_to_rtc_ticks(uint32_t timestamp_us)
|
||||
{
|
||||
const uint64_t rtc_ticks_in_femto_units = 30517578125UL;
|
||||
|
||||
return ((uint64_t)(timestamp_us) * 1000000000UL) / rtc_ticks_in_femto_units;
|
||||
}
|
||||
|
||||
uint64_t controller_time_us_get(void)
|
||||
{
|
||||
/* Simply use the RTC time here.
|
||||
* It is possible to combine RTC and TIMER information here to get a more accurate
|
||||
* timestamp. That requires setting up a PPI channel to capture both values simultaneously.
|
||||
*/
|
||||
|
||||
const uint64_t rtc_overflow_time_us = 512000000UL;
|
||||
|
||||
uint32_t captured_rtc_overflows;
|
||||
uint32_t captured_rtc_ticks;
|
||||
|
||||
while (true) {
|
||||
captured_rtc_overflows = num_rtc_overflows;
|
||||
|
||||
/* Read out RTC ticks after reading number of overflows. */
|
||||
barrier_isync_fence_full();
|
||||
|
||||
captured_rtc_ticks = nrf_rtc_counter_get(app_rtc_instance.p_reg);
|
||||
|
||||
/* Read out number of overflows after reading number of RTC ticks */
|
||||
barrier_isync_fence_full();
|
||||
|
||||
if (captured_rtc_overflows == num_rtc_overflows) {
|
||||
/* There were no new overflows after reading ticks.
|
||||
* That is, we can use the captured value.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rtc_ticks_to_us(captured_rtc_ticks) +
|
||||
(captured_rtc_overflows * rtc_overflow_time_us);
|
||||
}
|
||||
|
||||
void controller_time_trigger_set(uint64_t timestamp_us)
|
||||
{
|
||||
uint32_t num_overflows = timestamp_us / 512000000UL;
|
||||
uint64_t overflow_time_us = num_overflows * 512000000UL;
|
||||
|
||||
uint32_t remainder_time_us = timestamp_us - overflow_time_us;
|
||||
uint32_t rtc_val = us_to_rtc_ticks(remainder_time_us);
|
||||
uint8_t timer_val = timestamp_us - rtc_ticks_to_us(rtc_val);
|
||||
|
||||
/* Ensure the timer value lies between 1 and 30 so that it will
|
||||
* always be between two RTC ticks.
|
||||
*/
|
||||
timer_val = MAX(timer_val, 1);
|
||||
timer_val = MIN(timer_val, 30);
|
||||
|
||||
if (nrfx_rtc_cc_set(&app_rtc_instance, 0, rtc_val, false) != NRFX_SUCCESS) {
|
||||
printk("Failed setting trigger\n");
|
||||
}
|
||||
|
||||
nrfx_timer_compare(&app_timer_instance, 0, timer_val, false);
|
||||
nrfx_gppi_channels_enable(BIT(ppi_chan_on_rtc_match));
|
||||
}
|
||||
|
||||
uint32_t controller_time_trigger_event_addr_get(void)
|
||||
{
|
||||
return nrf_egu_event_address_get(NRF_EGU0, NRF_EGU_EVENT_TRIGGERED0);
|
||||
}
|
||||
|
||||
/* The controller time initialization must happen before
|
||||
* starting the network core.
|
||||
*/
|
||||
SYS_INIT(controller_time_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
*/
|
||||
|
||||
/** This file implements controller time management for 54 Series devices
|
||||
*/
|
||||
|
||||
// BK: taken from ncs/nrf/samples/bluetooth/conn_time_sync/src/controller_time_nrf54.c
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <nrfx_grtc.h>
|
||||
#include "controller_time.h"
|
||||
|
||||
static uint8_t grtc_channel;
|
||||
|
||||
int controller_time_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nrfx_grtc_channel_alloc(&grtc_channel);
|
||||
if (ret != NRFX_SUCCESS) {
|
||||
printk("Failed allocating GRTC channel (ret: %d)\n",
|
||||
ret - NRFX_ERROR_BASE_NUM);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
nrf_grtc_sys_counter_compare_event_enable(NRF_GRTC, grtc_channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t controller_time_us_get(void)
|
||||
{
|
||||
int ret;
|
||||
uint64_t current_time_us;
|
||||
|
||||
ret = nrfx_grtc_syscounter_get(¤t_time_us);
|
||||
if (ret != NRFX_SUCCESS) {
|
||||
printk("Failed obtaining system time (ret: %d)\n", ret - NRFX_ERROR_BASE_NUM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return current_time_us;
|
||||
}
|
||||
|
||||
void controller_time_trigger_set(uint64_t timestamp_us)
|
||||
{
|
||||
int ret;
|
||||
|
||||
nrfx_grtc_channel_t chan_data = {
|
||||
.channel = grtc_channel,
|
||||
};
|
||||
|
||||
ret = nrfx_grtc_syscounter_cc_absolute_set(&chan_data, timestamp_us, false);
|
||||
if (ret != NRFX_SUCCESS) {
|
||||
printk("Failed setting CC (ret: %d)\n", ret - NRFX_ERROR_BASE_NUM);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t controller_time_trigger_event_addr_get(void)
|
||||
{
|
||||
return nrf_grtc_event_address_get(NRF_GRTC,
|
||||
nrf_grtc_sys_counter_compare_event_get(grtc_channel));
|
||||
}
|
||||
|
||||
SYS_INIT(controller_time_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
||||
+283
-38
@@ -31,17 +31,15 @@
|
||||
#include <zephyr/bluetooth/buf.h>
|
||||
#include <zephyr/bluetooth/hci_raw.h>
|
||||
|
||||
// nRF5340 - from ncs/nrf/nrf5340_audio example
|
||||
#include <nrfx_timer.h>
|
||||
#include "audio_sync_timer.h"
|
||||
|
||||
// nRF54L15 - from ncs/nrf/samples/bluetooth/conn_time_sync
|
||||
#include "controller_time.h"
|
||||
|
||||
#define LOG_MODULE_NAME hci_uart
|
||||
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||
|
||||
static const struct device *const hci_uart_dev =
|
||||
DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_c2h_uart));
|
||||
static const struct device *const hci_uart_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_bt_c2h_uart));
|
||||
static const struct device *const gmap_uart_dev = DEVICE_DT_GET(DT_NODELABEL(uart1));
|
||||
|
||||
static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE);
|
||||
static struct k_thread tx_thread_data;
|
||||
static K_FIFO_DEFINE(tx_queue);
|
||||
@@ -70,6 +68,30 @@ static K_FIFO_DEFINE(uart_tx_queue);
|
||||
*/
|
||||
#define H4_DISCARD_LEN 33
|
||||
|
||||
#ifdef CONFIG_AUDIO_SYNC_TIMER_USES_RTC
|
||||
#define TIMESYNC_GPIO DT_NODELABEL(timesync)
|
||||
|
||||
#if DT_NODE_HAS_STATUS(TIMESYNC_GPIO, okay)
|
||||
static const struct gpio_dt_spec timesync_pin = GPIO_DT_SPEC_GET(TIMESYNC_GPIO, gpios);
|
||||
#else
|
||||
#error "No timesync gpio available!"
|
||||
#endif
|
||||
|
||||
#define ALTERNATE_TOGGLE_GPIO DT_NODELABEL(alternate_toggle)
|
||||
static const struct gpio_dt_spec alternate_toggle_pin = GPIO_DT_SPEC_GET(ALTERNATE_TOGGLE_GPIO, gpios);
|
||||
|
||||
#endif
|
||||
|
||||
// enable to have alternate toggle indicate time from audio in to sdu sync ref in UGT to UGG direction
|
||||
#define PERIPHERAL_TO_CENTRAL_AUDIO_IN_TO_SDU_SYNC_REF
|
||||
|
||||
// Presentation time from Audio to SDU Sync Ref (UGT->UGG) resp. SDU Sync Ref to Audio Out (UGG->UGT)
|
||||
// HS timer on nRF5340 seems to be off: 60000 ticks = 59372 us
|
||||
#define PRESENTATION_TIME_US 60634
|
||||
|
||||
static uint32_t last_sdu_sync_ref_us;
|
||||
static uint32_t sdu_interval_us;
|
||||
|
||||
static int h4_read(const struct device *uart, uint8_t *buf, size_t len)
|
||||
{
|
||||
int rx = uart_fifo_read(uart, buf, len);
|
||||
@@ -262,6 +284,15 @@ static void tx_thread(void *p1, void *p2, void *p3)
|
||||
|
||||
/* Wait until a buffer is available */
|
||||
buf = k_fifo_get(&tx_queue, K_FOREVER);
|
||||
|
||||
#if DT_NODE_HAS_STATUS(TIMESYNC_GPIO, okay)
|
||||
// toggle GPIO and send 'B' for each TX packet to be able to capture by Logic Analzyer
|
||||
if (bt_buf_get_type(buf) == BT_BUF_ISO_OUT) {
|
||||
gpio_pin_toggle_dt( ×ync_pin );
|
||||
uart_poll_out(gmap_uart_dev, 'B');
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Pass buffer to the stack */
|
||||
err = bt_send(buf);
|
||||
if (err!=BT_HCI_ERR_SUCCESS) {
|
||||
@@ -364,17 +395,7 @@ static int hci_uart_init(void)
|
||||
|
||||
SYS_INIT(hci_uart_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
|
||||
|
||||
#define ENABLE_ISO_TIMESYNC
|
||||
|
||||
#ifdef ENABLE_ISO_TIMESYNC
|
||||
|
||||
#define TIMESYNC_GPIO DT_NODELABEL(timesync)
|
||||
|
||||
#if DT_NODE_HAS_STATUS(TIMESYNC_GPIO, okay)
|
||||
static const struct gpio_dt_spec timesync_pin = GPIO_DT_SPEC_GET(TIMESYNC_GPIO, gpios);
|
||||
#else
|
||||
#error "No timesync gpio available!"
|
||||
#endif
|
||||
#ifdef CONFIG_AUDIO_SYNC_TIMER_USES_RTC
|
||||
|
||||
#define HCI_CMD_ISO_TIMESYNC (0x200)
|
||||
|
||||
@@ -391,12 +412,11 @@ uint8_t hci_cmd_iso_timesync_cb(struct net_buf *buf)
|
||||
LOG_INF("buf %p type %u len %u", buf, bt_buf_get_type(buf), buf->len);
|
||||
LOG_INF("buf[0] = 0x%02x", buf->data[0]);
|
||||
|
||||
uint32_t timestamp_second_us = 0;
|
||||
uint32_t timestamp_second_us;
|
||||
|
||||
// Lock interrupts to avoid interrupt between time capture and gpio toggle
|
||||
uint32_t key = arch_irq_lock();
|
||||
|
||||
#ifdef CONFIG_SOC_NRF5340_CPUAPP
|
||||
// Get current time
|
||||
uint32_t timestamp_first_us = audio_sync_timer_capture();
|
||||
|
||||
@@ -410,11 +430,6 @@ uint8_t hci_cmd_iso_timesync_cb(struct net_buf *buf)
|
||||
}
|
||||
timestamp_first_us = timestamp_second_us;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SOC_NRF54L15_CPUAPP) || defined(CONFIG_SOC_NRF52833)
|
||||
timestamp_second_us = (uint32_t) controller_time_us_get();
|
||||
#endif
|
||||
|
||||
#if DT_NODE_HAS_STATUS(TIMESYNC_GPIO, okay)
|
||||
gpio_pin_toggle_dt( ×ync_pin );
|
||||
@@ -439,14 +454,135 @@ uint8_t hci_cmd_iso_timesync_cb(struct net_buf *buf)
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t little_endian_read_16(const uint8_t * buffer, int position){
|
||||
return (uint16_t)(((uint16_t) buffer[position]) | (((uint16_t)buffer[position+1]) << 8));
|
||||
}
|
||||
|
||||
static uint32_t little_endian_read_32(const uint8_t * buffer, int position){
|
||||
return ((uint32_t) buffer[position]) | (((uint32_t)buffer[position+1]) << 8) | (((uint32_t)buffer[position+2]) << 16) | (((uint32_t) buffer[position+3]) << 24);
|
||||
}
|
||||
|
||||
#if DT_NODE_HAS_STATUS(TIMESYNC_GPIO, okay)
|
||||
|
||||
// make sure there's no IRQ between getting the time and the toggle
|
||||
// verify timestamp as it's 100% coorect
|
||||
#define LOCK_IRQS_FOR_SYNC_TOGGLE
|
||||
static uint32_t toggle_and_get_bluetooth_time_us(void) {
|
||||
uint32_t timestamp_toggle_us;
|
||||
|
||||
#ifdef LOCK_IRQS_FOR_SYNC_TOGGLE
|
||||
// Lock interrupts
|
||||
uint32_t key = arch_irq_lock();
|
||||
#endif
|
||||
|
||||
while (1){
|
||||
// Get current time once
|
||||
timestamp_toggle_us = audio_sync_timer_capture();
|
||||
|
||||
// Get current time again
|
||||
uint32_t timestamp_toggle_us_verify = audio_sync_timer_capture();
|
||||
|
||||
// check if time didn't jump
|
||||
int32_t timestamp_delta = (int32_t) (timestamp_toggle_us_verify - timestamp_toggle_us);
|
||||
if ((timestamp_delta >= 0) && (timestamp_delta < 10)){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle
|
||||
gpio_pin_toggle_dt( ×ync_pin );
|
||||
|
||||
#ifdef LOCK_IRQS_FOR_SYNC_TOGGLE
|
||||
// Unlock interrupts
|
||||
arch_irq_unlock(key);
|
||||
#endif
|
||||
|
||||
return timestamp_toggle_us;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define SYNC_TOGGLE_TIMER_INSTANCE_NUMBER 2
|
||||
static const nrfx_timer_t sync_toggle_timer_instance =
|
||||
NRFX_TIMER_INSTANCE(SYNC_TOGGLE_TIMER_INSTANCE_NUMBER);
|
||||
|
||||
|
||||
static nrfx_timer_config_t cfg = {.frequency = NRFX_MHZ_TO_HZ(1UL),
|
||||
.mode = NRF_TIMER_MODE_TIMER,
|
||||
.bit_width = NRF_TIMER_BIT_WIDTH_32,
|
||||
.interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY,
|
||||
.p_context = NULL};
|
||||
|
||||
static volatile enum {
|
||||
ALTERNATE_TOGGLE_STATE_IDLE,
|
||||
ALTERNATE_TOGGLE_STATE_W2_RISE,
|
||||
ALTERNATE_TOGGLE_STATE_W2_FALL
|
||||
} alternate_toggle_state = ALTERNATE_TOGGLE_STATE_IDLE;
|
||||
|
||||
static volatile uint32_t alternate_toggle_fall_us;
|
||||
|
||||
static uint32_t get_local_time_us(void) {
|
||||
nrf_timer_cc_set(NRF_TIMER2, NRF_TIMER_CC_CHANNEL2, 0);
|
||||
nrf_timer_task_trigger(NRF_TIMER2, nrf_timer_capture_task_get(NRF_TIMER_CC_CHANNEL2));
|
||||
uint32_t current_time_us = nrf_timer_cc_get(NRF_TIMER2, NRF_TIMER_CC_CHANNEL2);
|
||||
while (current_time_us == 0) {
|
||||
current_time_us = nrf_timer_cc_get(NRF_TIMER2, NRF_TIMER_CC_CHANNEL2);
|
||||
}
|
||||
return current_time_us;
|
||||
}
|
||||
|
||||
static void alternate_toggle_timer_isr_handler(nrf_timer_event_t event_type, void *p_context){
|
||||
ARG_UNUSED(p_context);
|
||||
if(event_type == NRF_TIMER_EVENT_COMPARE1){
|
||||
switch (alternate_toggle_state) {
|
||||
case ALTERNATE_TOGGLE_STATE_W2_RISE:
|
||||
alternate_toggle_state = ALTERNATE_TOGGLE_STATE_W2_FALL;
|
||||
gpio_pin_set_dt(&alternate_toggle_pin, 1);
|
||||
nrfx_timer_compare(&sync_toggle_timer_instance, NRF_TIMER_CC_CHANNEL1, alternate_toggle_fall_us, true);
|
||||
break;
|
||||
case ALTERNATE_TOGGLE_STATE_W2_FALL:
|
||||
alternate_toggle_state = ALTERNATE_TOGGLE_STATE_IDLE;
|
||||
gpio_pin_set_dt(&alternate_toggle_pin, 0);
|
||||
break;
|
||||
default:
|
||||
__ASSERT(0, "Unknown state");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void alternate_toggle_setup(uint32_t rise_us, uint32_t fall_us) {
|
||||
alternate_toggle_fall_us = fall_us;
|
||||
alternate_toggle_state = ALTERNATE_TOGGLE_STATE_W2_RISE;
|
||||
nrfx_timer_compare(&sync_toggle_timer_instance, NRF_TIMER_CC_CHANNEL1, rise_us, true);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// toggle timer setup
|
||||
nrfx_err_t ret;
|
||||
ret = nrfx_timer_init(&sync_toggle_timer_instance, &cfg, alternate_toggle_timer_isr_handler);
|
||||
if (ret - NRFX_ERROR_BASE_NUM) {
|
||||
LOG_ERR("nrfx timer init error: %d", ret);
|
||||
return -ENODEV;
|
||||
}
|
||||
IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TIMER_INST_GET(SYNC_TOGGLE_TIMER_INSTANCE_NUMBER)), IRQ_PRIO_LOWEST,
|
||||
NRFX_TIMER_INST_HANDLER_GET(SYNC_TOGGLE_TIMER_INSTANCE_NUMBER), 0, 0);
|
||||
nrfx_timer_enable(&sync_toggle_timer_instance);
|
||||
alternate_toggle_state = ALTERNATE_TOGGLE_STATE_IDLE;
|
||||
|
||||
/* incoming events and data from the controller */
|
||||
static K_FIFO_DEFINE(rx_queue);
|
||||
int err;
|
||||
|
||||
LOG_DBG("Start");
|
||||
__ASSERT(hci_uart_dev, "UART device is NULL");
|
||||
__ASSERT(hci_uart_dev, "HCI UART device is NULL");
|
||||
|
||||
if (!device_is_ready(gmap_uart_dev)) {
|
||||
printk("GMAP UART device is not ready\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Enable the raw interface, this will in turn open the HCI driver */
|
||||
bt_enable_raw(&rx_queue);
|
||||
@@ -477,7 +613,7 @@ int main(void)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ISO_TIMESYNC
|
||||
#ifdef CONFIG_AUDIO_SYNC_TIMER_USES_RTC
|
||||
/* Register iso_timesync command */
|
||||
static struct bt_hci_raw_cmd_ext cmd_list = {
|
||||
.op = BT_OP(BT_OGF_VS, HCI_CMD_ISO_TIMESYNC),
|
||||
@@ -489,6 +625,10 @@ int main(void)
|
||||
gpio_pin_configure_dt(×ync_pin, GPIO_OUTPUT_INACTIVE);
|
||||
#endif
|
||||
|
||||
#if DT_NODE_HAS_STATUS(TIMESYNC_GPIO, okay)
|
||||
gpio_pin_configure_dt(&alternate_toggle_pin, GPIO_OUTPUT_INACTIVE);
|
||||
#endif
|
||||
|
||||
bt_hci_raw_cmd_ext_register(&cmd_list, 1);
|
||||
#endif
|
||||
|
||||
@@ -500,20 +640,125 @@ int main(void)
|
||||
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
|
||||
k_thread_name_set(&tx_thread_data, "HCI uart TX");
|
||||
|
||||
#if 0
|
||||
while (1) {
|
||||
uint8_t c = 'A';
|
||||
uart_fifo_fill(hci_uart_dev, &c, 1);
|
||||
uart_irq_tx_enable(hci_uart_dev);
|
||||
k_sleep( K_MSEC(100) );
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
while (1) {
|
||||
struct net_buf *buf;
|
||||
|
||||
buf = k_fifo_get(&rx_queue, K_FOREVER);
|
||||
buf = net_buf_get(&rx_queue, K_FOREVER);
|
||||
|
||||
#if DT_NODE_HAS_STATUS(TIMESYNC_GPIO, okay)
|
||||
// ISO RX Measurement Code
|
||||
const uint8_t * packet = buf->data;
|
||||
if (packet[0] == H4_ISO){
|
||||
|
||||
// TODO: check if packets contains timestamp. all Controller -> Host packets have it so far
|
||||
|
||||
// get rx timestamp = sdu sync reference: Packet Type (1) | ISO Header (4) | Timestamp (if TS flag is set)
|
||||
const uint32_t timestamp_sdu_sync_reference_us = little_endian_read_32(packet, 5);
|
||||
|
||||
// ignore empty ISO packets
|
||||
const uint16_t data_total_length = little_endian_read_16(packet, 3);
|
||||
if (data_total_length > 8) {
|
||||
|
||||
// get current Bluetooth time + toggle GPIO
|
||||
const uint32_t bluetooth_time_us = toggle_and_get_bluetooth_time_us();
|
||||
|
||||
// calculate time of toggle relative to sdu sync reference usually
|
||||
// - negative for UGT->UGG and
|
||||
// - positive in UGT->UGG direction)
|
||||
const int32_t delta_us = (int32_t)(bluetooth_time_us - timestamp_sdu_sync_reference_us);
|
||||
|
||||
// convert to string and send over UART and RTT
|
||||
char delta_string[15];
|
||||
const uint8_t first_payload_byte = packet[13];
|
||||
snprintf(delta_string, sizeof(delta_string), "R%+06d@%02X!", delta_us,first_payload_byte);
|
||||
for (size_t i = 0; delta_string[i] != '\0'; i++) {
|
||||
uart_poll_out(gmap_uart_dev, delta_string[i]);
|
||||
}
|
||||
|
||||
LOG_INF("Toggle %8u - SDU Sync Reference %8u -> delta %s", bluetooth_time_us, timestamp_sdu_sync_reference_us, delta_string);
|
||||
}
|
||||
}
|
||||
|
||||
if (packet[0] == H4_EVT) {
|
||||
if (packet[1] == 0x0e) {
|
||||
uint16_t opcode = little_endian_read_16(packet, 4);
|
||||
const uint16_t hci_opcode_reset = 0x0c03;;
|
||||
if (opcode == hci_opcode_reset) {
|
||||
LOG_INF("HCI Reset");
|
||||
last_sdu_sync_ref_us = 0;
|
||||
sdu_interval_us = 0;
|
||||
}
|
||||
const uint16_t hci_opcode_le_read_tx_iso_sync = 0x2061;
|
||||
if (opcode == hci_opcode_le_read_tx_iso_sync) {
|
||||
const uint8_t * return_params = &packet[6];
|
||||
|
||||
// get current Bluetooth time + toggle GPIO
|
||||
const uint32_t bluetooth_time_us = toggle_and_get_bluetooth_time_us();
|
||||
|
||||
// get current local time
|
||||
const uint32_t local_time_us = get_local_time_us();
|
||||
|
||||
// status: 0
|
||||
uint16_t handle = little_endian_read_16(return_params, 1);
|
||||
ARG_UNUSED(handle);
|
||||
|
||||
// get packet sequence number (assuming counter == packet_sequence_number & 0xff)
|
||||
const uint16_t packet_sequence_number = little_endian_read_16(return_params, 3);
|
||||
|
||||
// get tx timestamp = sdu sync reference: Packet Type (1) | ISO Header (4) | Timestamp (if TS flag is set)
|
||||
const uint32_t iso_tx_us = little_endian_read_32(return_params, 5);
|
||||
|
||||
// get SDU interval based on sdu sync ref interval (round to the next 100 us)
|
||||
if (last_sdu_sync_ref_us > 0) {
|
||||
const uint32_t sdu_interval_reported_us = iso_tx_us - last_sdu_sync_ref_us;
|
||||
sdu_interval_us = ((sdu_interval_reported_us + 50) / 100 ) * 100;
|
||||
}
|
||||
last_sdu_sync_ref_us = iso_tx_us;
|
||||
|
||||
// calculate time of toggle relative to sdu sync reference (usually negative as the packet is received before it should be played)
|
||||
const int32_t delta_us = (int32_t)(bluetooth_time_us - iso_tx_us);
|
||||
|
||||
// convert to string and send over UART and RTT
|
||||
char delta_string[15];
|
||||
snprintf(delta_string, sizeof(delta_string), "T%+06d@%02X!", delta_us,packet_sequence_number & 0xff);
|
||||
for (size_t i = 0; delta_string[i] != '\0'; i++) {
|
||||
uart_poll_out(gmap_uart_dev, delta_string[i]);
|
||||
}
|
||||
// LOG_INF("Toggle %8u - TX %8u - %02X-> delta %s", bluetooth_time_us, iso_tx_us, packet_sequence_number, delta_string);
|
||||
|
||||
#ifdef PERIPHERAL_TO_CENTRAL_AUDIO_IN_TO_SDU_SYNC_REF
|
||||
// schedule Audio In to Sync Ref for Peripheral to Central direction
|
||||
if (sdu_interval_us > 0) {
|
||||
if (alternate_toggle_state == ALTERNATE_TOGGLE_STATE_IDLE) {
|
||||
|
||||
// note: for Peripheral to Central, the SDU Sync Ref matches the ISO TX Timestamp
|
||||
|
||||
// calculate next audio in time such that:
|
||||
// - it's in the future
|
||||
// - audio_in_us + presentatioon time = sdu_sync_ref
|
||||
uint32_t audio_in_us = iso_tx_us - PRESENTATION_TIME_US;
|
||||
while (audio_in_us < (bluetooth_time_us + 10000)) {
|
||||
audio_in_us += sdu_interval_us;
|
||||
}
|
||||
|
||||
// convert into local time reference
|
||||
const uint32_t rise_us = local_time_us + (audio_in_us - bluetooth_time_us);
|
||||
const uint32_t fall_us = rise_us + PRESENTATION_TIME_US;
|
||||
|
||||
// LOG_INF("bt %u, tx %u, audio in %u // sdu %u // now %u, rise %u",
|
||||
// bluetooth_time_us, iso_tx_us, audio_in_us,
|
||||
// sdu_interval_us,
|
||||
// local_time_us, rise_us);
|
||||
|
||||
alternate_toggle_setup(rise_us, fall_us);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
err = h4_send(buf);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to send");
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=8192
|
||||
CONFIG_MAIN_STACK_SIZE=2048
|
||||
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
|
||||
|
||||
CONFIG_MBOX=y
|
||||
CONFIG_IPC_SERVICE=y
|
||||
|
||||
CONFIG_BT=y
|
||||
CONFIG_BT_HCI_RAW=y
|
||||
CONFIG_BT_CTLR_ASSERT_HANDLER=y
|
||||
|
||||
CONFIG_BT_ISO_PERIPHERAL=y
|
||||
CONFIG_BT_ISO_CENTRAL=y
|
||||
CONFIG_BT_ISO_BROADCASTER=y
|
||||
CONFIG_BT_ISO_SYNC_RECEIVER=y
|
||||
CONFIG_BT_EXT_ADV=y
|
||||
CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER=y
|
||||
CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER=y
|
||||
|
||||
CONFIG_BT_CTLR_ADV_ISO_SET=2
|
||||
CONFIG_BT_CTLR_ADV_SET=2
|
||||
CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=2
|
||||
CONFIG_BT_CTLR_CONN_ISO_GROUPS=1
|
||||
CONFIG_BT_CTLR_CONN_ISO_STREAMS=2
|
||||
CONFIG_BT_CTLR_SYNC_ISO_STREAM_COUNT=3
|
||||
CONFIG_BT_CTLR_SYNC_PERIODIC_ADV_LIST_SIZE=1
|
||||
|
||||
|
||||
# Support six links as a central, or one link as a peripheral
|
||||
CONFIG_BT_MAX_CONN=8
|
||||
CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT=2
|
||||
|
||||
# Allow using more than default advertising event length
|
||||
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=251
|
||||
|
||||
# To present the audio at the right point in time, we need the controller and
|
||||
# audio clock to be synchronized
|
||||
CONFIG_MPSL_TRIGGER_IPC_TASK_ON_RTC_START=y
|
||||
CONFIG_MPSL_TRIGGER_IPC_TASK_ON_RTC_START_CHANNEL=4
|
||||
|
||||
# Needed for builds with nrf21540
|
||||
# Can also be set to 20, but check local restrictions first
|
||||
#CONFIG_BT_CTLR_TX_PWR_ANTENNA=10
|
||||
#CONFIG_MPSL_FEM_NRF21540_TX_GAIN_DB=10
|
||||
|
||||
CONFIG_IPC_RADIO_BT=y
|
||||
CONFIG_IPC_RADIO_BT_HCI_IPC=y
|
||||
@@ -1,58 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=8192
|
||||
CONFIG_MAIN_STACK_SIZE=2048
|
||||
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
|
||||
|
||||
CONFIG_MBOX=y
|
||||
CONFIG_IPC_SERVICE=y
|
||||
|
||||
CONFIG_BT=y
|
||||
CONFIG_BT_HCI_RAW=y
|
||||
CONFIG_BT_CTLR_ASSERT_HANDLER=y
|
||||
|
||||
CONFIG_BT_ISO_PERIPHERAL=y
|
||||
CONFIG_BT_ISO_CENTRAL=y
|
||||
CONFIG_BT_ISO_BROADCASTER=y
|
||||
CONFIG_BT_ISO_SYNC_RECEIVER=y
|
||||
CONFIG_BT_EXT_ADV=y
|
||||
CONFIG_BT_PER_ADV_SYNC_TRANSFER_RECEIVER=y
|
||||
CONFIG_BT_PER_ADV_SYNC_TRANSFER_SENDER=y
|
||||
|
||||
CONFIG_BT_CTLR_ADV_ISO_SET=2
|
||||
CONFIG_BT_CTLR_ADV_SET=2
|
||||
CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=2
|
||||
CONFIG_BT_CTLR_CONN_ISO_GROUPS=1
|
||||
CONFIG_BT_CTLR_CONN_ISO_STREAMS=2
|
||||
CONFIG_BT_CTLR_SYNC_ISO_STREAM_COUNT=3
|
||||
CONFIG_BT_CTLR_SYNC_PERIODIC_ADV_LIST_SIZE=1
|
||||
|
||||
# Support six links as a central, or one link as a peripheral
|
||||
CONFIG_BT_MAX_CONN=8
|
||||
CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT=2
|
||||
|
||||
# Allow using more than default advertising event length
|
||||
CONFIG_BT_CTLR_ADV_DATA_LEN_MAX=251
|
||||
|
||||
# To present the audio at the right point in time, we need the controller and
|
||||
# audio clock to be synchronized
|
||||
CONFIG_MPSL_TRIGGER_IPC_TASK_ON_RTC_START=y
|
||||
CONFIG_MPSL_TRIGGER_IPC_TASK_ON_RTC_START_CHANNEL=4
|
||||
|
||||
CONFIG_IPC_RADIO_BT=y
|
||||
CONFIG_IPC_RADIO_BT_HCI_IPC=y
|
||||
|
||||
# General
|
||||
CONFIG_DEBUG=n
|
||||
CONFIG_ASSERT=n
|
||||
CONFIG_STACK_USAGE=n
|
||||
CONFIG_THREAD_MONITOR=n
|
||||
CONFIG_SERIAL=n
|
||||
CONFIG_CONSOLE=n
|
||||
CONFIG_PRINTK=n
|
||||
CONFIG_UART_CONSOLE=n
|
||||
CONFIG_BOOT_BANNER=n
|
||||
Reference in New Issue
Block a user