20 Commits

Author SHA1 Message Date
pstruebi 3218a20d52 adaptions for auracaster 2025-02-13 16:57:36 +01:00
Matthias Ringwald dd84f76b59 Support time sync on nRF52833 DK 2025-01-10 17:47:28 +01:00
Matthias Ringwald 066fe6201b fix build for nRF52833DK 2025-01-10 17:47:08 +01:00
Matthias Ringwald e736be6ca4 readme: update 2025-01-10 09:27:00 +01:00
Matthias Ringwald 6bb8af2a3f readme: add nrf54l15 2025-01-09 18:11:19 +01:00
Matthias Ringwald ce657eb852 main: get us time on nrf54l 2025-01-09 18:10:13 +01:00
Matthias Ringwald db4e0e32c7 main: use ENABLE_ISO_TIMESYNC, allow compile without 2025-01-09 18:10:13 +01:00
Matthias Ringwald cf3d9e613a src: add get code to get controller time 2025-01-09 18:10:13 +01:00
Matthias Ringwald 4bfe9c07f6 prj.conf: config LE Audio for 54L15 2025-01-09 18:10:13 +01:00
Matthias Ringwald 5b94c9522d boards: use P1.11 as host timesync pin 2025-01-09 18:02:45 +01:00
Matthias Ringwald 779c31f97d boards: add nrf54l15 overlay files 2025-01-09 18:02:45 +01:00
Matthias Ringwald a82a9ff85a kconfig: fix spelling 2025-01-09 17:59:49 +01:00
Matthias Ringwald 2a89491008 update ipc_radio config for sysbuild / ncs 2.8 2024-12-17 16:56:42 +01:00
Matthias Ringwald caffd7b8a1 Update nRF5340 DK information 2024-12-12 15:30:59 +01:00
Matthias Ringwald b7dd60fd52 Add sysbuild configuration for required for NCS 2.8 2024-12-11 17:41:55 +01:00
Matthias Ringwald 16f411c7dc Update readme info on Time Sync GPIO pin mapping 2024-12-09 16:23:58 +01:00
Matthias Ringwald 427db6845b Block interrupts between time capture and toggle, verify time capture 2024-12-04 14:58:37 +01:00
Matthias Ringwald 2a0d2366b8 Enable SoftDevice support for Periodic Advertising Sync 2024-12-03 12:25:33 +01:00
Matthias Ringwald 0e041f1967 Update readme 2024-12-03 12:22:10 +01:00
Dirk Helbig 87bddccdd5 updated code for nRF Connect SDK v2.8.0 2024-12-03 12:22:10 +01:00
24 changed files with 1128 additions and 100 deletions
+2 -1
View File
@@ -1,7 +1,8 @@
.settings
.cproject
.project
build
build*/
app.jdebug
app.jdebug.user
*.jdebug.user
app.zip
+8 -2
View File
@@ -9,8 +9,14 @@ set(SRCS
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
)
if (CONFIG_AUDIO_SYNC_TIMER_USES_RTC)
list(APPEND SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/audio_sync_timer_rtc.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")
endif()
target_sources(app PRIVATE ${SRCS})
+1 -1
View File
@@ -4,7 +4,7 @@ menu "Modules"
rsource "Kconfig.defaults"
config AUDIO_SYNC_TIMER_USES_RTC
bool "Enables syncronization between the APP and NET core running SD"
bool "Enables synchronization between the APP and NET core running SD"
default !BT_LL_ACS_NRF53 && SOC_SERIES_NRF53X
select NRFX_RTC0
select NRFX_DPPI
+10
View File
@@ -0,0 +1,10 @@
#
# 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"
+126 -16
View File
@@ -1,61 +1,171 @@
# nRF5340 Bluetooth Controller with Support for LE ISO Timesync
This fork of the Zephyr HCI UART example adds a custom HCI Command to allow for timesync between the Bluetooth Host and the Bluetooth Controller. When the HCI LE Read ISO Clock command is received, the Controller toggles a GPIO and returns its current Bluetooth LE ISO Clock in the Command Complete Event.
This fork of the Zephyr HCI UART example adds a custom HCI Command to allow for timesync between the Bluetooth Host
and the Bluetooth Controller. When the HCI LE Read ISO Clock command is received, the Controller toggles a GPIO and
returns its current Bluetooth LE ISO Clock in the Command Complete Event.
It has been tested on the nRF5340 Audio DK, but it should work with any nRF5340 dev kit.
## Requirements
- nRF Connect SDK v2.8 or newer
## HCI LE Read ISO Clock Command
- OGF: 0x3f, OCF: 0x200
- Parameters: Flags (1 Octet) unused
- 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 -b nrf5340dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=usb.overlay -DOVERLAY_CONFIG=overlay-usb.conf
west build --pristine -b nrf5340dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=usb.overlay -DOVERLAY_CONFIG=overlay-usb.conf
```
_HCI over UART and timesync not tested._
### 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
## 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
west build -b nrf5340_audio_dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=usb.overlay -DOVERLAY_CONFIG=overlay-usb.conf
west build --pristine -b nrf5340_audio_dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=usb.overlay -DOVERLAY_CONFIG=overlay-usb.conf
```
### HCI over UART 0 connected to Virtual UART in J-Link Probe
```sh
west build -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
Release build:
```sh
west build -b nrf5340_audio_dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=uart1.overlay
west build --pristine -b nrf5340_audio_dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=uart1.overlay
```
Debug build:
```sh
west build -b nrf5340_audio_dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=uart1.overlay -DOVERLAY_CONFIG=debug.conf
west build --pristine -b nrf5340_audio_dk/nrf5340/cpuapp -- -DEXTRA_DTC_OVERLAY_FILE=uart1.overlay -DOVERLAY_CONFIG=debug.conf
```
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.
| 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 |
## 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.
+9
View File
@@ -0,0 +1,9 @@
#
# Copyright (c) 2024 Nordic Semiconductor
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
CONFIG_NRFX_TIMER1=y
CONFIG_NRFX_RTC2=y
CONFIG_NRFX_PPI=y
+11
View File
@@ -4,6 +4,17 @@
* 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>;
+9
View File
@@ -0,0 +1,9 @@
#
# 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
View File
@@ -2,3 +2,7 @@ CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="Zephyr HCI UART sample"
CONFIG_USB_CDC_ACM=y
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n
CONFIG_NRFX_TIMER1=y
CONFIG_NRFX_RTC2=y
CONFIG_NRFX_PPI=y
@@ -6,11 +6,7 @@
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 {
+23
View File
@@ -0,0 +1,23 @@
/*
* 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;
};
@@ -0,0 +1,33 @@
/*
* 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>;
};
+2 -1
View File
@@ -19,8 +19,9 @@ 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
# Support two links as a central, or one link as a peripheral
# Support six links as a central, or one link as a peripheral
CONFIG_BT_MAX_CONN=8
CONFIG_BT_CTLR_SDC_PERIPHERAL_COUNT=2
+3
View File
@@ -1,5 +1,8 @@
CONFIG_ASSERT=y
#CONFIG_BT_DEBUG_MONITOR_RTT=y # custom protocol - bluez needed
CONFIG_BT_DEBUG_MONITOR_RTT=y
#CONFIG_THREAD_NAME=y
#CONFIG_THREAD_ANALYZER=y
#CONFIG_THREAD_ANALYZER_AUTO=y
+3
View File
@@ -0,0 +1,3 @@
#! /bin/bash
nrfutil pkg generate --hw-version 52 --sd-req=0x00 --application ./build_nrf52dongle/merged.hex --application-version 1 app.zip
nrfutil device program --firmware app.zip --traits nordicDfu
+43 -14
View File
@@ -1,3 +1,23 @@
# Configure for multiple broadcasters
CONFIG_BT_EXT_ADV_MAX_ADV_SET=5
CONFIG_BT_CTLR_ADV_SET=5
CONFIG_BT_CTLR_ADV_ISO_SET=5
CONFIG_BT_CTLR_ADV_ISO_STREAM_COUNT=5
CONFIG_BT_CTLR_SYNC_ISO_STREAM_COUNT=5
CONFIG_BT_CTLR_ADV_ISO_STREAM_MAX=5
CONFIG_BT_CTLR_SYNC_PERIODIC_ADV_LIST_SIZE=5
CONFIG_BT_BUF_EVT_RX_COUNT=16
CONFIG_BT_CTLR_ADV_ISO_PDU_LEN_MAX=247
# ISO Transmissions
CONFIG_BT_CTLR_ISOAL_SOURCES=5
CONFIG_BT_CTLR_ISO_TX_BUFFERS=8
CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE=255
##
CONFIG_CONSOLE=n
CONFIG_STDOUT_CONSOLE=n
CONFIG_UART_CONSOLE=n
@@ -8,31 +28,41 @@ CONFIG_BT=y
CONFIG_BT_HCI_RAW=y
CONFIG_BT_HCI_RAW_H4=y
CONFIG_BT_HCI_RAW_H4_ENABLE=y
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
CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255
CONFIG_BT_CTLR_ASSERT_HANDLER=y
CONFIG_BT_MAX_CONN=16
#CONFIG_BT_MAX_CONN=16
CONFIG_BT_TINYCRYPT_ECC=n
CONFIG_BT_CTLR_DTM_HCI=y
# Enable ISO support
CONFIG_BT_ISO_PERIPHERAL=y
CONFIG_BT_ISO_CENTRAL=y
CONFIG_BT_ISO_BROADCASTER=y
# 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
# 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
# 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_SYSTEM_WORKQUEUE_STACK_SIZE=512
# Configure Controller
CONFIG_BT_CTLR_CONN_ISO_GROUPS=1
CONFIG_BT_CTLR_CONN_ISO_STREAMS=5
CONFIG_BT_CTLR_ADV_EXT=y
# 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=512
# Workaround: Unable to allocate command buffer when using K_NO_WAIT since
# Host number of completed commands does not follow normal flow control.
@@ -41,4 +71,3 @@ CONFIG_BT_BUF_CMD_TX_COUNT=10
# for the timesync command
CONFIG_BT_HCI_RAW_CMD_EXT=y
CONFIG_NRFX_TIMER2=y
+40
View File
@@ -0,0 +1,40 @@
/*
* 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
/**
* @}
*/
+292
View File
@@ -0,0 +1,292 @@
/*
* 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);
+270
View File
@@ -0,0 +1,270 @@
/*
* 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);
+68
View File
@@ -0,0 +1,68 @@
/*
* 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(&current_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);
+42 -60
View File
@@ -31,9 +31,12 @@
#include <zephyr/bluetooth/buf.h>
#include <zephyr/bluetooth/hci_raw.h>
#include <nrfx_timer.h>
// nRF5340 - from ncs/nrf/nrf5340_audio example
#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);
@@ -361,7 +364,10 @@ static int hci_uart_init(void)
SYS_INIT(hci_uart_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
#ifdef CONFIG_AUDIO_SYNC_TIMER_USES_RTC
#define ENABLE_ISO_TIMESYNC
#ifdef ENABLE_ISO_TIMESYNC
#define TIMESYNC_GPIO DT_NODELABEL(timesync)
#if DT_NODE_HAS_STATUS(TIMESYNC_GPIO, okay)
@@ -370,13 +376,6 @@ static const struct gpio_dt_spec timesync_pin = GPIO_DT_SPEC_GET(TIMESYNC_GPIO,
#error "No timesync gpio available!"
#endif
#define ALTERNATE_TOGGLE_GPIO DT_NODELABEL(alternate_toggle)
#if DT_NODE_HAS_STATUS(ALTERNATE_TOGGLE_GPIO, okay)
static const struct gpio_dt_spec alternate_toggle_pin = GPIO_DT_SPEC_GET(ALTERNATE_TOGGLE_GPIO, gpios);
#else
#warning "No alternate toggle gpio availabe!"
#endif
#define HCI_CMD_ISO_TIMESYNC (0x200)
struct hci_cmd_iso_timestamp_response {
@@ -392,15 +391,44 @@ 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]);
rsp = bt_hci_cmd_complete_create(BT_OP(BT_OGF_VS, HCI_CMD_ISO_TIMESYNC), sizeof(*response));
response = net_buf_add(rsp, sizeof(*response));
response->cc.status = BT_HCI_ERR_SUCCESS;
response->timestamp = audio_sync_timer_capture();
uint32_t timestamp_second_us = 0;
// 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();
while (1){
// get time again and verify that time didn't jump. Work around:
// https://devzone.nordicsemi.com/f/nordic-q-a/116907/bluetooth-netcore-time-capture-not-working-100-for-le-audio
timestamp_second_us = audio_sync_timer_capture();
int32_t timestamp_delta = (int32_t) (timestamp_second_us - timestamp_first_us);
if (timestamp_delta < 10){
break;
}
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( &timesync_pin );
#endif
// Unlock interrupts
arch_irq_unlock(key);
// emit event
rsp = bt_hci_cmd_complete_create(BT_OP(BT_OGF_VS, HCI_CMD_ISO_TIMESYNC), sizeof(*response));
response = net_buf_add(rsp, sizeof(*response));
response->cc.status = BT_HCI_ERR_SUCCESS;
response->timestamp = timestamp_second_us;
if (IS_ENABLED(CONFIG_BT_HCI_RAW_H4)) {
net_buf_push_u8(rsp, H4_EVT);
}
@@ -411,50 +439,8 @@ uint8_t hci_cmd_iso_timesync_cb(struct net_buf *buf)
}
#endif
#define TIME_TO_WAIT_MS 1000
#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 void sync_toggle_timer_isr_handler(nrf_timer_event_t event_type, void *p_context)
{
ARG_UNUSED(p_context);
if(event_type == NRF_TIMER_EVENT_COMPARE1)
{
char * p_msg = p_context;
uint32_t remainder_us = nrf_timer_cc_get(NRF_TIMER2,
NRF_TIMER_CC_CHANNEL1);
#if DT_NODE_HAS_STATUS(ALTERNATE_TOGGLE_GPIO, okay)
gpio_pin_toggle_dt( &alternate_toggle_pin );
#endif
LOG_INF("%d\n", remainder_us );
printf("Timer finished. Context passed to the handler: >%s<", p_msg);
}
}
int main(void)
{
// timer setup
nrfx_err_t ret;
ret = nrfx_timer_init(&sync_toggle_timer_instance, &cfg, sync_toggle_timer_isr_handler);
if (ret - NRFX_ERROR_BASE_NUM) {
LOG_ERR("nrfx timer init error: %d", ret);
return -ENODEV;
}
uint32_t desired_ticks = nrfx_timer_ms_to_ticks(&sync_toggle_timer_instance, TIME_TO_WAIT_MS);
nrfx_timer_compare(&sync_toggle_timer_instance, NRF_TIMER_CC_CHANNEL1, desired_ticks, true);
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);
/* incoming events and data from the controller */
static K_FIFO_DEFINE(rx_queue);
int err;
@@ -491,11 +477,7 @@ int main(void)
}
}
#if DT_NODE_HAS_STATUS(ALTERNATE_TOGGLE_GPIO, okay)
gpio_pin_configure_dt(&alternate_toggle_pin, GPIO_OUTPUT_INACTIVE);
#endif
#ifdef CONFIG_AUDIO_SYNC_TIMER_USES_RTC
#ifdef ENABLE_ISO_TIMESYNC
/* Register iso_timesync command */
static struct bt_hci_raw_cmd_ext cmd_list = {
.op = BT_OP(BT_OGF_VS, HCI_CMD_ISO_TIMESYNC),
+58
View File
@@ -0,0 +1,58 @@
#
# Copyright (c) 2023 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
# Addedby me
CONFIG_BT_EXT_ADV_MAX_ADV_SET=2
##
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
+58
View File
@@ -0,0 +1,58 @@
#
# 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
+12
View File
@@ -15,3 +15,15 @@
compatible = "zephyr,cdc-acm-uart";
};
};
/ {
host_interface {
compatible = "gpio-outputs";
status = "okay";
timesync: pin_0 {
gpios = <&gpio1 01 GPIO_ACTIVE_HIGH>;
label = "Controller to host timesync pin";
};
};
};