Hi,
I read the link https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/nrfx/drivers/twis/driver.html and updated periodic_sync example as attached below.
But I am unable to see Request from the Master. I checked connections, addresses and all.
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <zephyr.h>
#include <sys/byteorder.h>
#include <sys/printk.h>
#include <device.h>
#include <devicetree.h>
#include <drivers/gpio.h>
#include <bluetooth/bluetooth.h>
#include <dk_buttons_and_leds.h>
#include <device.h>
#include <soc.h>
#include <dk_buttons_and_leds.h>
#include <drivers/uart.h>
#include <drivers/i2c.h>
#include <nrfx_twi.h>
#include <nrfx_twis.h>
#include <devicetree.h>
#include <stdio.h>
#include <irq.h>
#include <settings/settings.h>
#define twi DT_LABEL(DT_ALIAS(i2c0))
uint8_t txBufferI2C[96];
#define SLAVE_ADDR (0x70 >> 1U)
#define DT_NORDIC_NRF_TWIS_I2C_0_IRQ_0 3
#define DT_NORDIC_NRF_TWIS_I2C_0_IRQ_0_PRIORITY 0
typedef nrfx_twis_t nrf_drv_twis_t;
static const nrfx_twis_t m_twis = NRFX_TWIS_INSTANCE(0);
const struct device *i2c_dev;
#define TIMEOUT_SYNC_CREATE K_SECONDS(10)
#define NAME_LEN 30
static bool per_adv_found;
static bt_addr_le_t per_addr;
static uint8_t per_sid;
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);
/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)
#if DT_NODE_HAS_STATUS(LED0_NODE, okay)
#define HAS_LED 0
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
#define BLINK_ONOFF K_MSEC(500)
static struct k_work_delayable blink_work;
static bool led_is_on;
static void blink_timeout(struct k_work *work)
{
led_is_on = !led_is_on;
gpio_pin_set(led.port, led.pin, (int)led_is_on);
k_work_schedule(&blink_work, BLINK_ONOFF);
}
#endif
static bool data_cb(struct bt_data *data, void *user_data)
{
char *name = user_data;
uint8_t len;
printk("\ndata_cb = %x len=%d",data->type,data->data_len);
memcpy(&txBufferI2C,&(data->type), 4); //add just to test so remove it
switch (data->type)
{
case BT_DATA_NAME_SHORTENED:
case BT_DATA_NAME_COMPLETE:
len = MIN(data->data_len, NAME_LEN - 1);
memcpy(name, data->data, len);
name[len] = '\0';
return false;
case BT_DATA_MANUFACTURER_DATA:
//printk("AAAAAAAAAAAAAAAAAAAAGGGG %d %s\n", data->data_len, data->data);
return true;
default:
return true;
}
}
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";
}
}
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[NAME_LEN];
(void)memset(name, 0, sizeof(name));
printk("\nscan_recv with len=%d, size=%d ",buf->len, buf->size);
bt_data_parse(buf, data_cb, name);
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
if (info->adv_type == 5)
printk("\n[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, info->interval * 5 / 4, info->sid);
if (!per_adv_found && info->interval) {
per_adv_found = true;
per_sid = info->sid;
bt_addr_le_copy(&per_addr, info->addr);
k_sem_give(&sem_per_adv);
}
}
static struct bt_le_scan_cb scan_callbacks = {
.recv = scan_recv,
};
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));
printk("\nsync_cb: PER_ADV_SYNC[%u]: [DEVICE]: %s synced, "
"Interval 0x%04x (%u ms), PHY %s\n",
bt_le_per_adv_sync_get_index(sync), le_addr,
info->interval, info->interval * 5 / 4, phy2str(info->phy));
k_sem_give(&sem_per_sync);
}
static void term_cb(struct bt_le_per_adv_sync *sync,
const struct bt_le_per_adv_sync_term_info *info)
{
char le_addr[BT_ADDR_LE_STR_LEN];
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
printk("\nterm_cb: PER_ADV_SYNC[%u]: [DEVICE]: %s sync terminated\n",
bt_le_per_adv_sync_get_index(sync), le_addr);
k_sem_give(&sem_per_sync_lost);
}
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)
{
char le_addr[BT_ADDR_LE_STR_LEN];
//char data_str[255];
bt_addr_le_to_str(info->addr, le_addr, sizeof(le_addr));
if (buf->data[1] == BT_DATA_ASHISH)
{
//bin2hex(buf->data, buf->len, data_str, sizeof(data_str));
memcpy(&txBufferI2C,&(buf->data[2]), (buf->len)-1);
printk("\n recv_cb: PER_ADV_SYNC[%u]: [DEVICE]: %s, tx_power %i, "
"RSSI %i, CTE %u, data length %u, data-type=%x \n",
bt_le_per_adv_sync_get_index(sync), le_addr, info->tx_power,
info->rssi, info->cte_type, buf->len,buf->data[1]);
printk("\n msg_data %x %x %x %x %x %x %x %x %x %x",buf->data[2],buf->data[3],buf->data[4],buf->data[5],buf->data[6],buf->data[7],buf->data[8],buf->data[9],buf->data[10],buf->data[11]);
}
else
{
printk("\n recv_cb: PER_ADV_SYNC[%u]: [DEVICE]: %s, tx_power %i, "
"RSSI %i, CTE %u, data length %u, data-type=%x \n",
bt_le_per_adv_sync_get_index(sync), le_addr, info->tx_power,
info->rssi, info->cte_type, buf->len,buf->data[1]);
}
}
static struct bt_le_per_adv_sync_cb sync_callbacks = {
.synced = sync_cb,
.term = term_cb,
.recv = recv_cb
};
static void twis_event_handler(nrfx_twis_evt_t const * const p_event)
{
printk("twis_event_handler\n");
switch (p_event->type)
{
case NRFX_TWIS_EVT_READ_REQ:
printk("NRFX_TWIS_EVT_READ_REQ\n");
if (p_event->data.buf_req)
{
(void)nrfx_twis_tx_prepare((nrfx_twis_t const *)&m_twis, &txBufferI2C[0], sizeof(txBufferI2C));
}
break;
case NRFX_TWIS_EVT_READ_DONE:
printk("NRFX_TWIS_EVT_READ_DONE\n");
// always keep last message in buffer, in case off I2C crc failure, on next I2C poll same data transmitted
break;
case NRFX_TWIS_EVT_WRITE_REQ:
printk("NRFX_TWIS_EVT_WRITE_REQ\n");
break;
case NRFX_TWIS_EVT_WRITE_DONE:
printk("NRFX_TWIS_EVT_WRITE_DONE\n");
break;
case NRFX_TWIS_EVT_READ_ERROR:
case NRFX_TWIS_EVT_WRITE_ERROR:
case NRFX_TWIS_EVT_GENERAL_ERROR:
printk("NRFX_TWIS_EVT_GENERAL_ERROR\n");
break;
default:
printk("DEFAULT\n");
break;
}
}
int I2CSlave_init(void)
{
int err;
IRQ_CONNECT(DT_NORDIC_NRF_TWIS_I2C_0_IRQ_0, DT_NORDIC_NRF_TWIS_I2C_0_IRQ_0_PRIORITY,
nrfx_isr, nrfx_twis_0_irq_handler, 0);
nrfx_twis_config_t config;
config.addr[0] = SLAVE_ADDR;
config.addr[1] = 0;
config.scl = 27;
config.scl_pull = NRF_GPIO_PIN_NOPULL;
config.sda = 26;
config.sda_pull = NRF_GPIO_PIN_NOPULL;
config.interrupt_priority = 0; // Highest
err = nrfx_twis_init(&m_twis, &config, twis_event_handler);
nrfx_twis_enable(&m_twis);
return err;
}
void main(void)
{
struct bt_le_per_adv_sync_param sync_create_param;
struct bt_le_per_adv_sync *sync;
int err;
printk("\nStarting Periodic Advertising Synchronization Demo\n");
/*i2c_dev = device_get_binding(DT_LABEL(DT_NODELABEL(i2c0)));
if (!i2c_dev) {
printk("I2C: Device driver not found.\n");
//return;
}*/
#if (HAS_LED)
printk("\nChecking LED device...");
if (!device_is_ready(led.port)) {
printk("\nfailed.\n");
return;
}
printk("\ndone.\n");
printk("\nConfiguring GPIO pin...");
err = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
if (err) {
printk("\nfailed.\n");
return;
}
printk("\ndone.\n");
k_work_init_delayable(&blink_work, blink_timeout);
#endif /* HAS_LED */
err = I2CSlave_init();
if (err != NRFX_SUCCESS) {
printk("I2C init failed (err %d)\n", err);
return;
}
/* Initialize the Bluetooth Subsystem */
err = bt_enable(NULL);
if (err) {
printk("\nBluetooth init failed (err %d)\n", err);
return;
}
printk("\nScan callbacks register...");
bt_le_scan_cb_register(&scan_callbacks);
printk("\nsuccess.\n");
printk("\nPeriodic Advertising callbacks register...");
bt_le_per_adv_sync_cb_register(&sync_callbacks);
printk("\nSuccess.\n");
printk("\nStart scanning...");
err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, NULL);
if (err) {
printk("\nfailed (err %d)\n", err);
return;
}
printk("\nsuccess.\n");
do {
#if (HAS_LED)
struct k_work_sync work_sync;
printk("\nStart blinking LED...\n");
led_is_on = false;
gpio_pin_set(led.port, led.pin, (int)led_is_on);
k_work_schedule(&blink_work, BLINK_ONOFF);
#endif /* HAS_LED */
printk("\nWaiting for periodic advertising...\n");
per_adv_found = false;
err = k_sem_take(&sem_per_adv, K_FOREVER);
if (err) {
printk("\nfailed (err %d)\n", err);
return;
}
printk("\nFound periodic advertising.\n");
printk("\nCreating Periodic Advertising Sync...");
bt_addr_le_copy(&sync_create_param.addr, &per_addr);
sync_create_param.options = 0;
sync_create_param.sid = per_sid;
sync_create_param.skip = 0;
sync_create_param.timeout = 0xa;
err = bt_le_per_adv_sync_create(&sync_create_param, &sync);
if (err) {
printk("\nfailed (err %d)\n", err);
return;
}
printk("\nsuccess.\n");
printk("\nWaiting for periodic sync...\n");
err = k_sem_take(&sem_per_sync, TIMEOUT_SYNC_CREATE);
if (err) {
printk("\nfailed (err %d)\n", err);
printk("\nDeleting Periodic Advertising Sync...");
err = bt_le_per_adv_sync_delete(sync);
if (err) {
printk("\nfailed (err %d)\n", err);
return;
}
continue;
}
printk("\nPeriodic sync established.\n");
#if (HAS_LED)
printk("\nStop blinking LED.\n");
k_work_cancel_delayable_sync(&blink_work, &work_sync);
/* Keep LED on */
led_is_on = true;
gpio_pin_set(led.port, led.pin, (int)led_is_on);
#endif /* HAS_LED */
printk("\nWaiting for periodic sync lost...\n");
err = k_sem_take(&sem_per_sync_lost, K_FOREVER);
if (err) {
printk("\nfailed (err %d)\n", err);
return;
}
printk("\nPeriodic sync lost.\n");
} while (true);
}
Can you please verify from your end or provide me some hint what could I miss?
I checked using Saleae logic analyzer and see it is always nak.
