Behaviour of PPI endpoint when using extended/periodic advertisement with CTE for direction finding

Hi,

This is a followup on https://devzone.nordicsemi.com/f/nordic-q-a/119259/synchronisation-between-tx-and-rx-in-connectionless-direction-finding 

We now have a synchronised counter being increment on TX and received at RX, which was the key issue in that post. Now, for additional accuracy in timing, we want to toggle a GPIO pin whenever a given packet with CTE is sent. 

In the current setup, I set up the advertisement configuration as follows

static struct bt_le_adv_param param = BT_LE_ADV_PARAM_INIT(BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_USE_IDENTITY,
                                                           BT_GAP_ADV_FAST_INT_MIN_1, BT_GAP_ADV_FAST_INT_MAX_1, NULL);

static struct bt_le_ext_adv_start_param ext_adv_start_param = {
    .timeout = 0,
    .num_events = 1,
};

static struct bt_le_per_adv_param per_adv_param = {
    .interval_min = BT_GAP_PER_ADV_FAST_INT_MIN_1,
    .interval_max = BT_GAP_PER_ADV_FAST_INT_MAX_1,
    .options = BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_NO_2M | BT_LE_ADV_OPT_USE_TX_POWER,
};

and set up the `adv_sent_cb` as

static void adv_sent_cb(struct bt_le_ext_adv *adv, struct bt_le_ext_adv_sent_info *info)
{
    int err;
    memcpy(&adv_data[8], &data_counter, sizeof(uint16_t));

    LOG_INF("Set Periodic Advertising Data to %d", data_counter);
    err = bt_le_per_adv_set_data(adv_set, ad, ARRAY_SIZE(ad));
    if (err)
    {
        LOG_ERR("Failed (err %d)\n", err);
    }

    serialise_counter(&protocol_data, data_counter);
    ble_protocol_data_send_and_clear_buffer(&protocol_data);

    // Guard against overflow
    if (data_counter < 65535)
    {
        data_counter++;
    }
    else
    {
        data_counter = 0;
    }

    LOG_INF("Extended advertising enable...");
    err = bt_le_ext_adv_start(adv_set, &ext_adv_start_param);
    if (err)
    {
        LOG_ERR("failed (err %d)\n", err);
        return;
    }

    LOG_INF("success\n");
}

This works and I am able to receive CTEs at the RX end.

However, with respect to the GPIO toggling, when I set up the following with the intention of toggling the GPIO whenever the payload has been sent with the updated counter value

void ppi_init(void)
{
    NRF_PPI->CH[1].EEP = (uint32_t)&NRF_RADIO->EVENTS_PAYLOAD;
    NRF_PPI->CH[1].TEP = (uint32_t)&NRF_EGU0->TASKS_TRIGGER[0];

    NRF_PPI->CHENSET = PPI_CHENSET_CH1_Set << PPI_CHENSET_CH1_Pos;
}

void egu_init(void)
{
    // Enable EGU interrupt
    NRF_EGU0->INTENSET = EGU_INTEN_TRIGGERED0_Msk;
    NVIC_SetPriority(SWI0_EGU0_IRQn, 6);
    NVIC_EnableIRQ(SWI0_EGU0_IRQn);
}

void SWI0_EGU0_IRQHandler(void)
{
    if (NRF_EGU0->EVENTS_TRIGGERED[0])
    {
        NRF_EGU0->EVENTS_TRIGGERED[0] = 0;

        LOG_DBG("Setting last sent data counter to %d (prev. value = %d)", data_counter, data_counter_last_sent);
    }
}

I get the following output, with the trigger happening five times per extended advertisement packet

but I was only expecting one. My suspicion that it may be related to the fact that periodic advertisement is enabled, but I am not entirely sure, and as far as I can tell, that needs to be active for the periodic sync which receives CTEs on the RX side to function as intended.

Hopefully I've provided sufficient information, please let me know if I need to add additional details!

Kind regards

Glen

Parents
  • And this is the only usage of the SWI0_EGU0_IRQHandler in your entire application? Have you confirmed that through debugging (setting a breakpoint there for example that this is only called once? Is there any chance your main() runs in a loop and thus calls this multiple times, or that IRQ_CONNECT is being called multiple times?

    Best regards,

    Simon

  • Hi again,

    I've not had much luck with the nRF Connect plugin debugger in the past, where we found it caused weird behaviour. We did some investigating, and found e.g., this https://stackoverflow.com/questions/63386189/whats-the-difference-between-a-compilers-o0-option-and-og-option which advises against using -Og (which is what debug optimisations in build configuration does here). 

    I did a new test now with setting up a new build configuration for debugging (I usually build via the terminal)

    This is based on the direction finding TX sample with AOA. This results in the board rebooting continuously with the following error

    Whereas with a normal build we receive CTEs from a single address with an incrementing counter on the RX side, as expected.

    if there is a workaround here, that would be great, but so far we've not had much luck trying to get this working.

    As for the point about main being called multiple times: Based on logging, it appears that the main function is only run through once during initialisation before multiple triggers occur on the TX side

    For completeness, here is the entire main function. 

    int main(void)
    {
        char addr_s[BT_ADDR_LE_STR_LEN];
        struct bt_le_oob oob_local;
        int err;
    
        LOG_INF("Starting TX");
        uint8_t serial_number[8];
        ssize_t length;
    
        length = hwinfo_get_device_id(serial_number, 8 * sizeof(uint8_t));
    
        if (length > 0)
        {
            for (int i = 0; i < length; i++)
            {
                adv_data[i] = serial_number[i];
            }
        }
        else
        {
            LOG_ERR("Failed to read serial number\n");
            return -1;
        }
    
        IRQ_CONNECT(SWI0_EGU0_IRQn, 6, SWI0_EGU0_IRQHandler, NULL, 0);
    
        gpiote_init();
        ppi_init();
        egu_init();
    
        /* Initialize the Bluetooth Subsystem */
        LOG_INF("Bluetooth initialization...");
        err = bt_enable(NULL);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("UART initialisation...\n");
        struct if_data *iface = if_initialisation();
        if (uart_config_get(iface->dev, &uart_cfg) != 0)
        {
            LOG_INF("UART initialisation failed");
            return -1;
        }
    
        LOG_INF("Protocol data struct initialisation...");
        if (ble_protocol_data_init(&protocol_data, iface) != 0)
        {
            LOG_ERR("Failed to iniitalised protocol data structj");
            return -1;
        }
        LOG_INF("Advertising set create...");
        err = bt_le_ext_adv_create(&param, &adv_callbacks, &adv_set);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        err = bt_le_ext_adv_set_data(adv_set, ad, ARRAY_SIZE(ad), NULL, 0);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
    
        LOG_INF("Update CTE params...");
        err = bt_df_set_adv_cte_tx_param(adv_set, &cte_params);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("Periodic advertising params set...");
        err = bt_le_per_adv_set_param(adv_set, &per_adv_param);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("Enable CTE...");
        err = bt_df_adv_cte_tx_enable(adv_set);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("Periodic advertising enable...");
        err = bt_le_per_adv_start(adv_set);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("Extended advertising enable...");
        err = bt_le_ext_adv_start(adv_set, &ext_adv_start_param);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("Get extended advertising address...");
        err = bt_le_ext_adv_oob_get_local(adv_set, &oob_local);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        bt_addr_le_to_str(&oob_local.addr, addr_s, sizeof(addr_s));
    
        LOG_INF("Started extended advertising as %s\n", addr_s);
    
    
    }

    Kind regards

    Glen

Reply
  • Hi again,

    I've not had much luck with the nRF Connect plugin debugger in the past, where we found it caused weird behaviour. We did some investigating, and found e.g., this https://stackoverflow.com/questions/63386189/whats-the-difference-between-a-compilers-o0-option-and-og-option which advises against using -Og (which is what debug optimisations in build configuration does here). 

    I did a new test now with setting up a new build configuration for debugging (I usually build via the terminal)

    This is based on the direction finding TX sample with AOA. This results in the board rebooting continuously with the following error

    Whereas with a normal build we receive CTEs from a single address with an incrementing counter on the RX side, as expected.

    if there is a workaround here, that would be great, but so far we've not had much luck trying to get this working.

    As for the point about main being called multiple times: Based on logging, it appears that the main function is only run through once during initialisation before multiple triggers occur on the TX side

    For completeness, here is the entire main function. 

    int main(void)
    {
        char addr_s[BT_ADDR_LE_STR_LEN];
        struct bt_le_oob oob_local;
        int err;
    
        LOG_INF("Starting TX");
        uint8_t serial_number[8];
        ssize_t length;
    
        length = hwinfo_get_device_id(serial_number, 8 * sizeof(uint8_t));
    
        if (length > 0)
        {
            for (int i = 0; i < length; i++)
            {
                adv_data[i] = serial_number[i];
            }
        }
        else
        {
            LOG_ERR("Failed to read serial number\n");
            return -1;
        }
    
        IRQ_CONNECT(SWI0_EGU0_IRQn, 6, SWI0_EGU0_IRQHandler, NULL, 0);
    
        gpiote_init();
        ppi_init();
        egu_init();
    
        /* Initialize the Bluetooth Subsystem */
        LOG_INF("Bluetooth initialization...");
        err = bt_enable(NULL);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("UART initialisation...\n");
        struct if_data *iface = if_initialisation();
        if (uart_config_get(iface->dev, &uart_cfg) != 0)
        {
            LOG_INF("UART initialisation failed");
            return -1;
        }
    
        LOG_INF("Protocol data struct initialisation...");
        if (ble_protocol_data_init(&protocol_data, iface) != 0)
        {
            LOG_ERR("Failed to iniitalised protocol data structj");
            return -1;
        }
        LOG_INF("Advertising set create...");
        err = bt_le_ext_adv_create(&param, &adv_callbacks, &adv_set);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        err = bt_le_ext_adv_set_data(adv_set, ad, ARRAY_SIZE(ad), NULL, 0);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
    
        LOG_INF("Update CTE params...");
        err = bt_df_set_adv_cte_tx_param(adv_set, &cte_params);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("Periodic advertising params set...");
        err = bt_le_per_adv_set_param(adv_set, &per_adv_param);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("Enable CTE...");
        err = bt_df_adv_cte_tx_enable(adv_set);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("Periodic advertising enable...");
        err = bt_le_per_adv_start(adv_set);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("Extended advertising enable...");
        err = bt_le_ext_adv_start(adv_set, &ext_adv_start_param);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        LOG_INF("Get extended advertising address...");
        err = bt_le_ext_adv_oob_get_local(adv_set, &oob_local);
        if (err)
        {
            LOG_ERR("failed (err %d)\n", err);
            return 0;
        }
        LOG_INF("success\n");
    
        bt_addr_le_to_str(&oob_local.addr, addr_s, sizeof(addr_s));
    
        LOG_INF("Started extended advertising as %s\n", addr_s);
    
    
    }

    Kind regards

    Glen

Children
No Data
Related