5340 many periodic advertiser sync error -5

the code, i can create one periodic adv, and i can get 45 aoa sample, but when i turn on another tag, i got err -5 from "err = bt_le_per_adv_sync_create(&(obj.sync_create_param), &(obj.sync));". the error like:

how to understand the " <wrn> bt_hci_core: opcode 0x2044 status 0x07". this is my main.c code like:

/*
 * Copyright (c) 2021 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

#include <stddef.h>
#include <errno.h>
#include <zephyr/kernel.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/direction.h>

#include <zephyr/drivers/gpio.h>

// LOG日志模块引入
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);
#define LOG_D(format, ...) LOG_DBG(">(%d)" format, __LINE__, ##__VA_ARGS__)
#define LOG_W(format, ...) LOG_WRN(">(%d)" format, __LINE__, ##__VA_ARGS__)
#define LOG_E(format, ...) LOG_ERR(">(%d)" format, __LINE__, ##__VA_ARGS__)

#include "wk_list.h"
#include "uart.h"

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
#define PEER_NAME_LEN_MAX 30
/* BT Core 5.3 specification allows controller to wait 6 periodic advertising events for
 * synchronization establishment, hence timeout must be longer than that.
 */
#define SYNC_CREATE_TIMEOUT_INTERVAL_NUM 7
/* Maximum length of advertising data represented in hexadecimal format */
#define ADV_DATA_HEX_STR_LEN_MAX (BT_GAP_ADV_MAX_EXT_ADV_DATA_LEN * 2 + 1)

static struct bt_le_per_adv_sync *sync;
// 标签MAC地址
static bt_addr_le_t per_addr;
static volatile bool per_adv_found;
static bool scan_enabled;
// 周期性广播对象的SID
static uint8_t per_sid;
static uint32_t sync_create_timeout_ms;

static K_SEM_DEFINE(sem_per_adv, 0, 1);
static K_SEM_DEFINE(sem_per_sync, 0, 1);
static K_SEM_DEFINE(sem_per_sync_lost, 0, 1);

// LED模块引入
#define LED_SLEEP_TIME_MS 1000
#define LED0_NODE DT_ALIAS(led0)
#define LED1_NODE DT_ALIAS(led1)
static const struct gpio_dt_spec led0 = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
static const struct gpio_dt_spec led1 = GPIO_DT_SPEC_GET(LED1_NODE, gpios);

// BTN模块引入
#define BUTTON_0_NODE DT_ALIAS(boot_button0)
#if DT_NODE_EXISTS(BUTTON_0_NODE) && DT_NODE_HAS_PROP(BUTTON_0_NODE, gpios)
static const struct gpio_dt_spec button0 = GPIO_DT_SPEC_GET(BUTTON_0_NODE, gpios);
#else
#error "button must be declared in device tree as 'mcuboot_button0'"
#endif

// 使能天线切换开关(接收端AoA)
#if defined(CONFIG_BT_DF_CTE_RX_AOA)
/* Example sequence of antenna switch patterns for antenna matrix designed by
 * Nordic. For more information about antenna switch patterns see README.rst.
 */
// Nordic官方参数.
// static const uint8_t ant_patterns[] = {0x2, 0x0, 0x5, 0x6, 0x1, 0x4, 0xC, 0x9, 0xE, 0xD, 0x8, 0xA};
// 吾控参数.默认在数组[0],即天线9上接收扩展广播,当周期性广播后面有CTE时,就顺序切换天线1~天线8
const static uint8_t ant_patterns[] = {0x04, 0x0B, 0x0C, 0x0E, 0x00, 0x02, 0x07, 0x08, 0x0A};
#endif /* CONFIG_BT_DF_CTE_RX_AOA */

/**
 * @brief 周期性广播间隔转毫秒
 *
 * @param interval
 * @return uint32_t
 */
static inline uint32_t adv_interval_to_ms(uint16_t interval)
{
	return interval * 5 / 4;
}

/**
 * @brief phy类型
 *
 * @param phy
 * @return const char*
 */
static const char *phy2str(uint8_t phy)
{
	switch (phy)
	{
	case 0:
		return "No packets";
	case BT_GAP_LE_PHY_1M:
		return "LE 1M";
	case BT_GAP_LE_PHY_2M:
		return "LE 2M";
	case BT_GAP_LE_PHY_CODED:
		return "LE Coded";
	default:
		return "Unknown";
	}
}

/**
 * @brief CTE类型
 *
 * @param type
 * @return const char*
 */
static const char *cte_type2str(uint8_t type)
{
	switch (type)
	{
	case BT_DF_CTE_TYPE_AOA:
		return "AOA";
	case BT_DF_CTE_TYPE_AOD_1US:
		return "AOD 1 [us]";
	case BT_DF_CTE_TYPE_AOD_2US:
		return "AOD 2 [us]";
	case BT_DF_CTE_TYPE_NONE:
		return "";
	default:
		return "Unknown";
	}
}

/**
 * @brief 包状态
 *
 * @param status
 * @return const char*
 */
static const char *packet_status2str(uint8_t status)
{
	switch (status)
	{
	case BT_DF_CTE_CRC_OK:
		return "CRC OK";
	case BT_DF_CTE_CRC_ERR_CTE_BASED_TIME:
		return "CRC not OK, CTE Info OK";
	case BT_DF_CTE_CRC_ERR_CTE_BASED_OTHER:
		return "CRC not OK, Sampled other way";
	case BT_DF_CTE_INSUFFICIENT_RESOURCES:
		return "No resources";
	default:
		return "Unknown";
	}
}

/**
 * @brief 解析广播数据(三段式)
 *
 * @param data
 * @param user_data
 * @return true
 * @return false
 */
static bool data_cb(struct bt_data *data, void *user_data)
{
	char *name = user_data;
	uint8_t len;

	switch (data->type)
	{
	case BT_DATA_NAME_SHORTENED:
	case BT_DATA_NAME_COMPLETE:
		len = MIN(data->data_len, PEER_NAME_LEN_MAX - 1);
		memcpy(name, data->data, len);
		name[len] = '\0';
		return false;
	default:
		return true;
	}
}

/**
 * @brief 周期性广播同步完成后的回调函数(如果标签在基站附近,理论上只需要同步一次即可,也就是回调执行一次,后面就是收数据/关连接/IQ采样行为)
 *
 * @param sync
 * @param info
 */
static void sync_cb(struct bt_le_per_adv_sync *sync, struct bt_le_per_adv_sync_synced_info *info)
{
	char le_addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));

	LOG_D("sync_cb[%u]: [DEVICE]: %s synced, "
		  "Interval 0x%04x (%u ms), PHY %s\n",
		  bt_le_per_adv_sync_get_index(sync), le_addr, info->interval, adv_interval_to_ms(info->interval), phy2str(info->phy));
	// 同步完成给出信号量(主函数中接收信号量,并使能CTE接收)
	k_sem_give(&sem_per_sync);
}

// 对象同步丢失FIFO
static K_FIFO_DEFINE(fifo_sync_lost_obj_data);
struct sync_lost_data_t
{
	// 对象
	struct bt_le_per_adv_sync *sync_obj;
	// 对象地址
	uint8_t addr[BT_ADDR_LE_STR_LEN];
};
/**
 * @brief 关闭周期性同步完成(标签断电/离开这个区域了)
 *
 * @param sync
 * @param info
 */
static void term_cb(struct bt_le_per_adv_sync *sync, const struct bt_le_per_adv_sync_term_info *info)
{
	struct sync_lost_data_t *sync_lost_data = k_malloc(sizeof(struct sync_lost_data_t));
	if (sync_lost_data)
	{
		sync_lost_data->sync_obj = sync;
		memcpy(sync_lost_data->addr, info->addr->a.val, BT_ADDR_SIZE);
	}
	// 关闭完成给出信号量(主函数中接收信号量,并删除该同步对象)
	k_fifo_put(&fifo_sync_lost_obj_data, sync_lost_data);
}

/**
 * @brief 周期性广播接收数据完成
 *
 * @param sync
 * @param info
 * @param buf
 */
static void recv_cb(struct bt_le_per_adv_sync *sync, const struct bt_le_per_adv_sync_recv_info *info, struct net_buf_simple *buf)
{
	static char data_str[ADV_DATA_HEX_STR_LEN_MAX];
	char le_addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
	bin2hex(buf->data, buf->len, data_str, sizeof(data_str));
	// LOG_D("recv_cb[%u]: [DEVICE]: %s, tx_power %i, RSSI %i, CTE %s, data length %u, data: %s\n", bt_le_per_adv_sync_get_index(sync), le_addr, info->tx_power, info->rssi, cte_type2str(info->cte_type), buf->len, data_str);
}

/**
 * @brief IQ采样完成
 *
 * @param sync
 * @param report
 */
static void cte_recv_cb(struct bt_le_per_adv_sync *sync, struct bt_df_per_adv_sync_iq_samples_report const *report)
{
	LOG_D("cte_recv_cb[%u]: samples count %d, cte type %s, slot durations: %u [us], packet status %s, RSSI %i\n", bt_le_per_adv_sync_get_index(sync), report->sample_count, cte_type2str(report->cte_type), report->slot_durations, packet_status2str(report->packet_status), report->rssi);
}

// 周期性广播同步回调
static struct bt_le_per_adv_sync_cb sync_callbacks = {
	.synced = sync_cb,			  /* 同步已成功 */
	.term = term_cb,			  /* 同步已关闭(本机关闭/远程请求关闭/远距离丢数据引起的关闭) */
	.recv = recv_cb,			  /* 数据已提取 */
	.cte_report_cb = cte_recv_cb, /*IQ采样已成功*/
};

/**
 * @brief 扫描回调函数
 *
 * @param info
 * @param buf
 */
static void scan_recv(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf)
{
	char le_addr[BT_ADDR_LE_STR_LEN];
	char name[PEER_NAME_LEN_MAX];

	(void)memset(name, 0, sizeof(name));

	// 提取标签的名称
	bt_data_parse(buf, data_cb, name);
	// 提取标签的地址
	bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));

	// LOG_D("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i %s C:%u S:%u "
	// 	   "D:%u SR:%u E:%u Prim: %s, Secn: %s, Interval: 0x%04x (%u ms), "
	// 	   "SID: %u\n",
	// 	   le_addr, info->adv_type, info->tx_power, info->rssi, name,
	// 	   (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0,
	// 	   (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0,
	// 	   (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0,
	// 	   (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0,
	// 	   (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0, phy2str(info->primary_phy),
	// 	   phy2str(info->secondary_phy), info->interval, adv_interval_to_ms(info->interval),
	// 	   info->sid);
	// LOG_D("[DEVICE]: %s\r\n", le_addr);


	// 有间隔则说明是周期性广播
	if (/*!per_adv_found && */ info->interval)
	{
		/* 记录新来的标签MAC,插入到list,如果长时间无周期性广播,则删除它 */
		gpio_pin_toggle_dt(&led0);
		// LOG_D("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i %s C:%u S:%u "
		// 	   "D:%u SR:%u E:%u Prim: %s, Secn: %s, Interval: 0x%04x (%u ms), "
		// 	   "SID: %u\n",
		// 	   le_addr, info->adv_type, info->tx_power, info->rssi, name,
		// 	   (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0,
		// 	   (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0,
		// 	   (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0,
		// 	   (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0,
		// 	   (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0, phy2str(info->primary_phy),
		// 	   phy2str(info->secondary_phy), info->interval, adv_interval_to_ms(info->interval),
		// 	   info->sid);

		// 同步超时时间
		sync_create_timeout_ms = adv_interval_to_ms(info->interval) * SYNC_CREATE_TIMEOUT_INTERVAL_NUM;
		per_adv_found = true;
		per_sid = info->sid;
		bt_addr_le_copy(&per_addr, info->addr);
		// 给出信号量,立即开始同步
		k_sem_give(&sem_per_adv);
	}
}

/**
 * @brief 发现有了周期性广播,就创建一个东西(obj)来处理周期性广播同步
 *
 */
static void create_sync(void)
{
	struct bt_le_per_adv_sync_param sync_create_param;
	int err;

	LOG_D("Creating Periodic Advertising Sync...");
	// 标签地址拷贝
	bt_addr_le_copy(&sync_create_param.addr, &per_addr);
	// 需要有CTE才同步(没有CTE则不同步)
	sync_create_param.options = 0;
	// 广播者的set id
	sync_create_param.sid = per_sid;
	// 通过“最大事件跳过”这个参数,扫描设备可以在成功接收到一个周期性广播事件后,选择跳过一定数量的连续周期性广播事件,以达到节省功耗或提高扫描效率的目的
	sync_create_param.skip = 0;
	// 同步超时100ms
	sync_create_param.timeout = 0x64; // 0xa;
	// 创建周期性广播同步对象,用于同步周期性广播的上报.
	err = bt_le_per_adv_sync_create(&sync_create_param, &sync);
}

// 扫描回调
static struct bt_le_scan_cb scan_callbacks = {
	.recv = scan_recv,
};

/**
 * @brief 删除处理周期性广播同步的obj
 *
 * @return int
 */
static int delete_sync(void)
{
	int err;

	LOG_D("Deleting Periodic Advertising Sync...");
	// 删除周期性广播同步对象
	err = bt_le_per_adv_sync_delete(sync);
	if (err)
	{
		LOG_D("failed (err %d)\n", err);
		return err;
	}
	LOG_D("success\n");

	return 0;
}

/**
 * @brief 使能cte
 *
 */
static void enable_cte_rx(void)
{
	int err;

	const struct bt_df_per_adv_sync_cte_rx_param cte_rx_params = {
		.max_cte_count = 5, /* CTE次数,与标签对应上即可 */
		/* BT_DF_CTE_TYPE_AOA   BT_DF_CTE_TYPE_ALL */
		.cte_types = BT_DF_CTE_TYPE_ALL,					/* 支持aoa/aod1us/aod2us三种类型 */
		.slot_durations = BT_DF_ANTENNA_SWITCHING_SLOT_2US, /* 开关切换使用2us槽 */
		.num_ant_ids = ARRAY_SIZE(ant_patterns),			/* 天线数量 */
		.ant_ids = ant_patterns,							/* 天线数组 */
	};

	LOG_D("%s():enable receiving of CTE.\r\n", __func__);
	// 使能接收,采样CTE信号
	err = bt_df_per_adv_sync_cte_rx_enable(sync, &cte_rx_params);
	if (err)
	{
		LOG_D("failed (err %d)\n", err);
		return;
	}
	LOG_D("success. CTE receive enabled.\n");
}

/**
 * @brief 扫描初始化
 *
 * @return int
 */
static int scan_init(void)
{
	LOG_D("Scan callbacks register...");
	// 注册扫描回调函数(primary channel)
	bt_le_scan_cb_register(&scan_callbacks);
	LOG_D("success.\n");

	LOG_D("Periodic Advertising callbacks register...");
	// 注册周期性广播回调函数(secondary channel)
	bt_le_per_adv_sync_cb_register(&sync_callbacks);
	LOG_D("success.\n");

	return 0;
}

/**
 * @brief 使能扫描
 *
 * @return int
 */
static int scan_enable(void)
{
	struct bt_le_scan_param param = {
		.type = BT_LE_SCAN_TYPE_ACTIVE, /*扫描,并request额外信息*/
		.options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
		/*BT_LE_SCAN_OPT_NONE*/ /*不过滤*/
		/*BT_LE_SCAN_OPT_FILTER_DUPLICATE*/
		.interval = BT_GAP_SCAN_FAST_INTERVAL, /* 扫描间隔60ms */
		.window = BT_GAP_SCAN_FAST_WINDOW,	   /* 扫描窗30ms */
		.timeout = 0U,
	};

	int err;

	if (!scan_enabled)
	{
		LOG_D("Start scanning...");
		err = bt_le_scan_start(&param, NULL);
		if (err)
		{
			LOG_D("failed (err %d)\n", err);
			return err;
		}
		LOG_D("success\n");
		scan_enabled = true;
	}

	return 0;
}

static void scan_disable(void)
{
	int err;

	LOG_D("Scan disable...");
	err = bt_le_scan_stop();
	if (err)
	{
		LOG_D("failed (err %d)\n", err);
		return;
	}
	LOG_D("Success.\n");

	scan_enabled = false;
}

/**
 * @brief 判定是否应该进入升级模式(button0开机就被按下)
 *
 * @return true -进入升级模式
 * @return false -不进入升级模式
 */
static bool is_enter_boot_mode(void)
{
	int pin_active;

	if (!device_is_ready(button0.port))
	{
		return false;
	}

	gpio_pin_configure_dt(&button0, GPIO_INPUT);
	pin_active = gpio_pin_get_dt(&button0);

	LOG_DBG("0button0 = %d.", pin_active);

	if (pin_active)
	{
		k_sleep(K_MSEC(50));
		LOG_DBG("button0 = %d.", pin_active);
		if (pin_active == gpio_pin_get_dt(&button0))
			return true;
		else
			return false;
	}
	return false;
}

int main(void)
{
	/* 延时等待片外外设起来 */
	k_msleep(1000);

	int err;

	if (!gpio_is_ready_dt(&led0) || !gpio_is_ready_dt(&led1))
	{
		return 0;
	}

	gpio_pin_configure_dt(&led0, GPIO_OUTPUT_ACTIVE);
	gpio_pin_configure_dt(&led1, GPIO_OUTPUT_ACTIVE);
	gpio_pin_configure_dt(&button0, GPIO_INPUT);

	gpio_pin_set_dt(&led0, GPIO_ACTIVE_HIGH);
	gpio_pin_set_dt(&led1, GPIO_ACTIVE_HIGH);

	// 获取构建信息
	//  memset(bulid_msg, 0, sizeof(bulid_msg));
	//  sprintf(bulid_msg, "BR,%04d%02d%02d-%02d%02d%02d,%s\r\n", OS_YEAR, OS_MONTH, OS_DAY, OS_HOUR, OS_MINUTE, OS_SECOND, FIREWARE_VERSION);
	//  usart1SendStringDma(bulid_msg);

	LOG_INF("hello %s, build time:" __DATE__ " " __TIME__ "\n", CONFIG_BOARD);

	/* 检查是否是升级模式 */
	if (gpio_pin_get_dt(&button0))
	{
		gpio_pin_set_dt(&led1, GPIO_ACTIVE_LOW);
		LOG_INF("enter boot mode.");
		extern void wk_dfu_uart_thread_create(void);
		wk_dfu_uart_thread_create();
		return 0;
	}

	gpio_pin_set_dt(&led0, GPIO_ACTIVE_LOW);
	LOG_INF("enter application mode.");

	// 初始化串口
	uart_init();
	// 创建接收线程
	extern void uart_thread_create(void);
	uart_thread_create();

	uint8_t data[10] = {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30};
	for (int i = 0; i < 100; i++)
	{
		uart_hex_print(data, sizeof(data));
		uart_print("hello app0 %d, build time:" __DATE__ " " __TIME__ "\r\n", i, CONFIG_BOARD);
	}

	k_msleep(1000);

	LOG_D("Starting Connectionless Locator Demo\n");
	LOG_D("Bluetooth initialization...");
	err = bt_enable(NULL);
	if (err)
	{
		LOG_D("failed (err %d)\n", err);
	}
	LOG_D("success\n");

	// 扫描初始化(处理扫描回调(primary)/处理周期性广播回调(secondary))
	scan_init();
	scan_enable();

	while (true)
	{
		k_msleep(100);
		gpio_pin_toggle_dt(&led1);
	}
}

/**
 * @brief 周期性广播对象创建
 *
 */
void create_sync_thread(void)
{
	int err;
	k_msleep(100);

	while (1)
	{
		// 等待周期性广播信号量(可能会丢对象)
		err = k_sem_take(&sem_per_adv, K_FOREVER);
		if (err)
		{
			LOG_D("failed (err %d)\n", err);
			continue;
		}

		// 临时对象
		struct per_adv_obj obj;

		/* 遍历链表确认是否已经存在该对象 */
		// 提取对象地址
		memcpy(obj.mac.addr, per_addr.a.val, BT_ADDR_SIZE);
		// 遍历
		err = wk_list_search_per_adv_obj(obj);
		if (!err)
		{
			// LOG_D("obj already exist continue.");
			continue;
		}
		LOG_D("new obj comming.");
		// 周期性广播对象的参数
		struct bt_le_per_adv_sync_param sync_create_param;
		// 标签地址拷贝
		bt_addr_le_copy(&(obj.sync_create_param.addr), &per_addr);
		// 需要有CTE才同步(没有CTE则不同%E6%AD%A5)
		obj.sync_create_param.options = 0;
		// 广播者的set id
		obj.sync_create_param.sid = per_sid;
		// 通过“最大事件跳过”这个参数,扫描设备可以在成功接收到一个周期性广播事件后,选择跳过一定数量的连续周期性广播事件,以达到节省功耗或提高扫描效率的目的
		obj.sync_create_param.skip = 0;
		// 同步超时100ms
		obj.sync_create_param.timeout = 0x64; // 0xa;
		// 创建周期性广播同步对象,用于同步周期性广播的上报.
		err = bt_le_per_adv_sync_create(&(obj.sync_create_param), &(obj.sync));
		if (err)
		{
			LOG_D("sync create failed (err %d)\n", err);
			continue;
		}

		/* 等待周期性广播成功 */
		err = k_sem_take(&sem_per_sync, K_MSEC(sync_create_timeout_ms));
		if (err)
		{
			// 删除周期性广播同步对象
			bt_le_per_adv_sync_delete(obj.sync);
			continue;
		}
		LOG_D("success. Periodic sync established.\n");

		/* 使能CTE */
		const struct bt_df_per_adv_sync_cte_rx_param cte_rx_params = {
			.max_cte_count = 5, /* CTE次数,与标签对应上即可 */
			/* BT_DF_CTE_TYPE_AOA   BT_DF_CTE_TYPE_ALL */
			.cte_types = BT_DF_CTE_TYPE_ALL,					/* 支持aoa/aod1us/aod2us三种类型 */
			.slot_durations = BT_DF_ANTENNA_SWITCHING_SLOT_2US, /* 开关切换使用2us槽 */
			.num_ant_ids = ARRAY_SIZE(ant_patterns),			/* 天线数量 */
			.ant_ids = ant_patterns,							/* 天线数组 */
		};
		// 使能接收,采样CTE信号
		err = bt_df_per_adv_sync_cte_rx_enable(obj.sync, &cte_rx_params);
		if (err)
		{
			LOG_D("enable cet rx failed (err %d)\n", err);
			continue;
		}

		/* 将对象添加到链表 */
		wk_list_add_per_adv_obj(obj);
		// 遍历链表
		wk_list_foreach_per_adv_obj();
	}
}
K_THREAD_DEFINE(create_sync_thread_id, 2024, create_sync_thread, NULL, NULL, NULL, 9, 0, 0);

/**
 * @brief 周期性广播对象删除
 *
 */
void delete_sync_thread(void)
{
	int err;
	k_msleep(100);

	while (1)
	{
		// 一直等待获取同步关闭的对象(标签断电/离开这个区域了)
		struct sync_lost_data_t *sync_lost_obj = k_fifo_get(&fifo_sync_lost_obj_data, K_FOREVER);
		// 删除周期性广播同步对象
		err = bt_le_per_adv_sync_delete(sync_lost_obj->sync_obj);
		LOG_D("bt_le_per_adv_sync_delete err = %d", err);

		// 临时对象
		struct per_adv_obj obj;
		// 提取对象地址
		memcpy(obj.mac.addr, sync_lost_obj->addr, BT_ADDR_SIZE);
		// 释放内存
		k_free(sync_lost_obj);
		// 删除链表
		err = wk_list_del_per_adv_obj(obj);
		LOG_D("wk_list_del_per_adv_obj err = %d", err);
	}
}
K_THREAD_DEFINE(delete_sync_thread_id, 2024, delete_sync_thread, NULL, NULL, NULL, 9, 0, 0);

how can i write the code for many tags.

Parents
  • Hi,

    It seems you have exceeded the maximum amount of simultaneous tags. The status code you get (0x7) is BT_HCI_ERR_MEM_CAPACITY_EXCEEDED. Probably your CONFIG_BT_PER_ADV_SYNC_MAX is set to 45?

    45 is a high number, though. How many tags do you intend to support simultaneously?

  • i can get 45 aoa sample

    the '45' means 45 IQ samples for aoa algorithm, not for periodic adv!  in my prj.conf, 'CONFIG_BT_PER_ADV_SYNC_MAX=6'

    How many tags do you intend to support simultaneously?

    10Hz about 20 tags is ok for me. this is my prj.conf file:

    #
    # Copyright (c) 2021 Nordic Semiconductor ASA
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    
    CONFIG_BT=y
    CONFIG_BT_DEVICE_NAME="DF Connectionless Locator App"
    
    CONFIG_BT_EXT_ADV=y
    CONFIG_BT_PER_ADV_SYNC=y
    CONFIG_BT_OBSERVER=y
    
    # Enable Direction Finding Feature including AoA and AoD
    CONFIG_BT_DF=y
    CONFIG_BT_DF_CONNECTIONLESS_CTE_RX=y
    
    
    
    ###############################################
    # ----------------------------------CONSOLE功能配置
    # 开启控制台
    CONFIG_CONSOLE=y
    # # 使能printk作为控制台输出
    CONFIG_PRINTK=y
    
    # # 方案1.使用jlink的rtt作为输出
    # # 1.1使能jlink
    CONFIG_USE_SEGGER_RTT=y
    # # 1.2使能jlink作为控制台输出
    CONFIG_RTT_CONSOLE=y
    
    # # 方案2.使能uart作为控制台输出
    # # 2.1使能uart
    # CONFIG_SERIAL=n
    # # 2.2使能uart作为控制台输出
    # CONFIG_UART_CONSOLE=n
    
    # ----------------------------------LOG功能配置
    # 使能LOG
    CONFIG_LOG=y
    # 使用jlink的rtt作为LOG的后端
    CONFIG_LOG_BACKEND_RTT=n
    # 使用uart作为LOG的后端
    CONFIG_LOG_BACKEND_UART=n
    
    # ----------------------------------SHELL功能配置
    # 使能shell
    CONFIG_SHELL=y
    CONFIG_SHELL_MINIMAL=n
    CONFIG_SHELL_STACK_SIZE=4024
    CONFIG_SHELL_BACKEND_SERIAL=n
    CONFIG_THREAD_MONITOR=y
    CONFIG_BOOT_BANNER=y
    CONFIG_THREAD_NAME=y
    CONFIG_SHELL_BACKEND_RTT=y
    CONFIG_SHELL_PROMPT_RTT=""
    
    # ----------------------------------DFU
    # 使能串口
    CONFIG_SERIAL=y
    # 使能异步API
    CONFIG_UART_ASYNC_API=y
    CONFIG_NRFX_UARTE0=y
    # 使能串口中断(和异步API只能二选一)
    # CONFIG_UART_INTERRUPT_DRIVEN=y
    
    
    # Enable the LittleFS file system.
    # CONFIG_FILE_SYSTEM=y
    CONFIG_FLASH=y
    # CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    # CONFIG_FILE_SYSTEM_LITTLEFS=y
    
    CONFIG_REBOOT=y
    
    CONFIG_STREAM_FLASH=y
    CONFIG_IMG_MANAGER=y
    
    # ----------------------------------其它重要配置
    # 堆大小设置,使用k_malloc时从此2048上获取
    CONFIG_HEAP_MEM_POOL_SIZE=40240
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1025
    
    ########################################
    CONFIG_BT_PER_ADV_SYNC_MAX=6
    
    # 仅支持串口升级
    CONFIG_BOOTLOADER_MCUBOOT=y
    

    now i have 2 tags, only one tag can be synced. it is confused me.

  • upupsky said:
    the '45' means 45 IQ samples for aoa algorithm, not for periodic adv!  in my prj.conf, 'CONFIG_BT_PER_ADV_SYNC_MAX=6'

    I see, that makes more sense. 45 tags/beacond would be a high number Slight smile. I assume 45 is an arbitrary number then, and that if you had waited longer before turning on the tag you would have received more? So that the problem is with supporting more than 1 tag?

    Are you running the application on the application core? Does it work if you build and run the whole application on the network core instead? (remember to program the empty app core image on the application core in that case). The reason I ask is that the BT_HCI_ERR_MEM_CAPACITY_EXCEEDED seems to indicate some buffer problem of some sort, and that could also be on the network core (hci_rpmsg) image.

  • 45 tags/beacond would be a high number

    45 tags, very tag periodic interval is 200ms. it is necessary for indoor location sense use aoa.

    if you had waited longer before turning on the tag you would have received more?

    no i can not receive more. because i got error -5 already, when turn on the second tag. so i can still get the first tag.

    running the application on the application core?

    yes, i run application on the application core. network core use the default conf. this is my network core prj.conf code:

    CONFIG_IPC_SERVICE=y
    CONFIG_MBOX=y
    
    CONFIG_HEAP_MEM_POOL_SIZE=8192
    
    CONFIG_MAIN_STACK_SIZE=512
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=512
    
    CONFIG_BT=y
    CONFIG_BT_HCI_RAW=y
    CONFIG_BT_HCI_RAW_RESERVE=1
    CONFIG_BT_MAX_CONN=16
    
    
    # Workaround: Unable to allocate command buffer when using K_NO_WAIT since
    # Host number of completed commands does not follow normal flow control.
    CONFIG_BT_BUF_CMD_TX_COUNT=10
    
    # Enable and adjust the below value as necessary
    # 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
    

    and the child_image/hci_rpmsg.conf code:

    #
    # Copyright (c) 2021 Nordic Semiconductor ASA
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    
    # Required to enable BT_BUF_CMD_TX_SIZE for LE Set Extended Advertising Data command
    CONFIG_BT_EXT_ADV=y
    
    # Required to enable BT_PER_ADV_SYNC_MAX
    CONFIG_BT_PER_ADV_SYNC=y
    CONFIG_BT_OBSERVER=y
    
    CONFIG_BT_CTLR=y
    CONFIG_BT_LL_SW_SPLIT=y
    
    CONFIG_BT_CTLR_ADV_EXT=y
    CONFIG_BT_CTLR_SYNC_PERIODIC=y
    
    # Enable Direction Finding Feature including AoA and AoD
    CONFIG_BT_CTLR_DF=y
    CONFIG_BT_CTLR_DF_ANT_SWITCH_TX=n
    
    # Disable Direction Finding TX mode
    CONFIG_BT_CTLR_DF_ADV_CTE_TX=n
    
    # Limit number of possible connection to decrease memory usage
    CONFIG_BT_MAX_CONN=1
    

    in hci_rpmsg.conf, "# Required to enable BT_PER_ADV_SYNC_MAX" it seems "CONFIG_BT_PER_ADV_SYNC_MAX=30" may solve my problem. but can i add the macro in application core?

    Does it work if you build and run the whole application on the network core instead?

    i will do as you said later, it maybe solve the problem.

  • in hci_rpmsg.conf, "# Required to enable BT_PER_ADV_SYNC_MAX" it seems "CONFIG_BT_PER_ADV_SYNC_MAX=30" may solve my problem. but can i add the macro in application core?

    i add "CONFIG_BT_PER_ADV_SYNC_MAX=2" in the network core, but got error, RAM overflowed:

    but "CONFIG_BT_PER_ADV_SYNC_MAX=1"  is ok (it means the default value). how can i do next? thanks.

  • now i add "CONFIG_BT_PER_ADV_SYNC_MAX=30" in the application core, not network core. complie ok, but still error = -5.

  • (remember to program the empty app core image on the application core in that case)

    i use empty app core, and blinky in  net core, it works well, this means my operation is ok.  But sample "direction_finding_connectionless_rx" on net core like"

    got error like:

    why?

Reply Children
  • Hi,

    Checking more it turns out that running on only the network core is not supported and will not work due to memory constraints.

    Moreover, even getting 2 is a challenge, as you saw when you added CONFIG_BT_PER_ADV_SYNC_MAX=2 to hci_rpmsg.conf, as that makes you run out of RAM on the network core. So other optimizations are needed, for instance adjust CONFIG_HEAP_MEM_POOL_SIZE=2048 (I did not test extensively but I did not get any problems immediately with this configuration). You can also try to optimize the network core memory usage elsewhere by other Kconfigs. A higher number may also be possible with a lot of optimization, but you will not realistically be able to support more than a few.

    Edit: There seems to be a bug that causes an incorrect buffer allocation, that increases the memory usage more than needed. With this change, you can set a higher CONFIG_BT_PER_ADV_SYNC_MAX for the network core (in hci_rpmsg.conf):

    diff --git a/subsys/bluetooth/controller/ll_sw/ull_df_types.h b/subsys/bluetooth/controller/ll_sw/ull_df_types.h
    index f75b54bef7..9b98897071 100644
    --- a/subsys/bluetooth/controller/ll_sw/ull_df_types.h
    +++ b/subsys/bluetooth/controller/ll_sw/ull_df_types.h
    @@ -28,7 +28,7 @@ enum df_switch_sample_support {
      * - for ULL -> LL(HCI).
      */
     #if defined(CONFIG_BT_PER_ADV_SYNC_MAX) && defined(CONFIG_BT_CTLR_DF_PER_SCAN_CTE_NUM_MAX)
    -#define SYNC_IQ_REPORT_CNT (CONFIG_BT_PER_ADV_SYNC_MAX * CONFIG_BT_CTLR_DF_PER_SCAN_CTE_NUM_MAX * 2)
    +#define SYNC_IQ_REPORT_CNT (CONFIG_BT_CTLR_DF_PER_SCAN_CTE_NUM_MAX * 2)
     #else
     #define SYNC_IQ_REPORT_CNT 0U
     #endif

  • i test this code, but get error too. direction_finding_connectionless_rx_multiple. can you give any suggesstions?

    (ncs sdk v2.5 or v2.4 are the same errors)
    
    `[20:04:08.447]收←◆*** Booting Zephyr OS build v3.3.99-ncs1-1-g2e59638ecf8b ***
    Starting Connectionless Locator Demo
    Bluetooth initialization...success
    
    [20:04:14.433]收←◆C Creating Sync:[DEVICE]: 10:73:7D:11:C7:A5 (random) ...success.
    
    [20:04:16.614]收←◆S PER_ADV_SYNC[0]: [DEVICE]: 10:73:7D:11:C7:A5 (random) synced, Interval 0x0780 (2400 ms), PHY LE 2M
    E [DEVICE]: 10:73:7D:11:C7:A5 (random) enabling CTE ... XE enable_cte_rx failed -5
    D Deleting Sync of [DEVICE]: ?
    T PER_ADV_SYNC[0]: [DEVICE]: 10:73:7D:11:C7:A5 (random) sync terminated
    
    [20:04:16.744]收←◆C Creating Sync:[DEVICE]: 10:73:7D:11:C7:A5 (random) ...success.
    E [DEVICE]: 10:73:7D:11:C7:A5 (random) enabling CTE ... XE enable_cte_rx failed -22
    D Deleting Sync of [DEVICE]: €
    
    [20:04:17.074]收←◆C Creating Sync:[DEVICE]: 10:73:7D:11:C7:A5 (random) ...success.
    
    [20:04:19.014]收←◆S PER_ADV_SYNC[0]: [DEVICE]: 10:73:7D:11:C7:A5 (random) synced, Interval 0x0780 (2400 ms), PHY LE 2M
    E [DEVICE]: 10:73:7D:11:C7:A5 (random) enabling CTE ... XE enable_cte_rx failed -5
    D Deleting Sync of [DEVICE]: ?
    T PER_ADV_SYNC[0]: [DEVICE]: 10:73:7D:11:C7:A5 (random) sync terminated
    
    [20:04:19.164]收←◆C Creating Sync:[DEVICE]: 10:73:7D:11:C7:A5 (random) ...success.
    E [DEVICE]: 10:73:7D:11:C7:A5 (random) enabling CTE ... XE enable_cte_rx failed -22
    D Deleting Sync of [DEVICE]: €?
    
    [20:04:19.384]收←◆C Creating Sync:[DEVICE]: 10:73:7D:11:C7:A5 (random) ...success.

    any problem on my enviroments?

  • I have not seen this repository before and it is not made by Nordic, but this is quite old and I suspect it is based on nRF Connect SDK 1.8.0. I would also be very surprised if this was tested (and working) on the nRF5340 (though more recent versions of the original sample in Zephyr is).

  • yeah, i use sdk 1.8.0 tested. there are no errors, but still can not support 2 tags.

    [12:03:10.723]收←◆CTE[0]: [DEVICE]: 02:03:15:BC:53:89 (random), samples count 82, cte type AOA, slot durations: 1 [us], packet status CRC OK, RSSI -1270
    
    [12:03:13.123]收←◆CTE[0]: [DEVICE]: 02:03:15:BC:53:89 (random), samples count 82, cte type AOA, slot durations: 1 [us], packet status CRC OK, RSSI -1270
    
    [12:03:15.524]收←◆CTE[0]: [DEVICE]: 02:03:15:BC:53:89 (random), samples count 82, cte type AOA, slot durations: 1 [us], packet status CRC OK, RSSI -1270
    
    [12:03:17.923]收←◆CTE[0]: [DEVICE]: 02:03:15:BC:53:89 (random), samples count 82, cte type AOA, slot durations: 1 [us], packet status CRC OK, RSSI -1270
    
    [12:03:18.313]收←◆C	Creating Sync:[DEVICE]: 02:D2:70:53:C7:14 (random) ...success.
    
    [12:03:20.322]收←◆S	PER_ADV_SYNC[1]: [DEVICE]: 02:D2:70:53:C7:14 (random) synced, Interval 0x0780 (2400 ms), PHY LE 2M
    CTE[0]: [DEVICE]: 02:03:15:BC:53:89 (random), samples count 82, cte type AOA, slot durations: 1 [us], packet status CRC OK, RSSI -1270
    E	[DEVICE]: 02:D2:70:53:C7:14 (random) enabling CTE ... success.
    
    [12:03:20.604]收←◆CTE[0]: [DEVICE]: 02:03:15:BC:53:89 (random), samples count 82, cte type AOA, slot durations: 1 [us], packet status CRC OK, RSSI -1270
    
    [12:03:25.123]收←◆CTE[0]: [DEVICE]: 02:03:15:BC:53:89 (random), samples count 82, cte type AOA, slot durations: 1 [us], packet status CRC OK, RSSI -1270

  • when find aoa tag, the github sample code called the function "err = create_sync(&(synch_addr.addr), synch_addr.sid,  &(synch_info.synch_ptr));" but the synch obj are the

    same, is this right?

    		if (atomic_cas(&sync_flag, candid_sync, ongoing_sync)) {
    			err = create_sync(&(synch_addr.addr), synch_addr.sid,
    					&(synch_info.synch_ptr));
    			if (err != 0) {
    				bt_addr_le_to_str(&(synch_addr.addr), le_addr, sizeof(le_addr));
    				printk("XC\tCreating sync [DEVICE]: %s failed (err %d)\n", le_addr, err);
    				/* give a fresh scan */
    				scan_disable();
    				/* start from begining of the loop again */
    				continue;
    			} else {
    				/* set timestamp and create the synch obj */
    				synch_info.timestamp = k_uptime_get();
    			}
    		} else {
    			/* give a fresh scan */
    			scan_disable();
    			/* start from begining of the loop again */
    			continue;
    		}

Related