nRF52840 BLE 3-Wire PTA for Wi-Fi

Hello DevZone,

I'm developing nRF52840 BLE & ESP32 Wi-Fi coexistence with 3-Wire PTA. I followed this document: https://docs.nordicsemi.com/bundle/ncs-2.5.3/page/nrf/device_guides/wifi_coex.html#generic_three_wire_coexistence

However, the NCS only support generic 3-wire PTA for OpenThread. So, I decided to write my own PTA code.

I modified `peripheral_uart` example. Added my code (with MPSL CX API).

The MPSL code is not difficult to understand. I referred to nrf/subsys/mpsl/cx/thread/mpsl_cx_thread.c

and nrf/subsys/mpsl/cx/nrf700x/mpsl_cx_nrf700x.c.

You can check my code as attached.

1488.peripheral_uart.7z

If you want to run this code, use NCS 2.5.3. And add the following Kconfig chioce to MPSL_CX_CHOICE in nrf/subsys/mpsl/cx/Kconfig 

config MPSL_CX_BT_3WIRE
    depends on SOC_SERIES_NRF52X
    select NRFX_GPIOTE
	select GPIO
	select NRFX_TIMER1
	bool "Bluetooth Radio 3-Wire Coexistence"

The problem is that the BLE activity is not controlled by the GRANT pin

No matter how I change the GRANT pin, the BLE connection is always good. And it never controls the REQUEST pin and PRIORITY pin.

Best regards,

Jayant

Parents
  • Hi,

    The generic three-wire coex implementation (CONFIG_MPSL_CX_THREAD), despite the confusing name, also supports BLE as it implements the MPSL generic coex API (https://docs.nordicsemi.com/bundle/ncs-2.5.3/page/nrf/device_guides/wifi_coex.html#ug-radio-coex-mpsl-cx-based)

    Try to enable CONFIG_MPSL_CX_THREAD=y in prj.conf instead to see if this protocol works for your requirements.

    Regards,
    Amanda H.

  • Hi Amanda,

    This config CONFIG_MPSL_CX_THREAD=y does not work.

    By default, it can't be enabled in BLE samples, because the nrf/subsys/mpsl/cx/Kconfig says this Kconfig `depends on !BT`. So, I deleted the line `depends on !BT`. 

    The REQUEST pin and PRIORITY pin still not change state. And I can't connect to the DK with my nRF Connect App. The BLE advertising stopped just after startup.

     Best regards,

    Jayant

  • I have some updates.

    1. I find out that the MPSL does not call the `register_callback` function. So, my code didn't get the callback function.  

    2. I tried a different way to enable 3-wire PTA in MPSL. I referred to nrf/subsys/mpsl/cx/bluetooth/mpsl_cx_1w_bluetooth.c

    It doesn't work, too.

    You can replace the same name file in my project (previously provided) with this file.

    /*
     * Copyright (c) 2022 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    /**
     * @file
     *   This file implements a generic bluetooth external radio 3w coexistence
     *   interface.
     *
     */
    
    #include <stddef.h>
    #include <stdint.h>
    
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/gpio.h>
    #include <zephyr/devicetree.h>
    #include <nrfx.h>
    #include <nrfx_ppi.h>
    #include <nrfx_gpiote.h>
    
    #include <mpsl_coex.h>
    
    #if DT_NODE_HAS_STATUS(DT_PHANDLE(DT_NODELABEL(radio), coex), okay)
    #define COEX_NODE DT_PHANDLE(DT_NODELABEL(radio), coex)
    #else
    #define COEX_NODE DT_INVALID_NODE
    #error No enabled coex nodes registered in DTS.
    #endif
    
    #if !(DT_NODE_HAS_COMPAT(COEX_NODE, generic_radio_coex_three_wire))
    #error Selected coex node is not compatible with generic-radio-coex-three-wire.
    #endif
    
    #if !IS_ENABLED(CONFIG_SOC_SERIES_NRF52X)
    #error Bluetooth 3-wire coex is only supported on the nRF52 series
    #endif
    
    #define MPSL_COEX_BT_GPIO_POLARITY_GET(dt_property)                                                \
    	((GPIO_ACTIVE_LOW & DT_GPIO_FLAGS(COEX_NODE, dt_property)) ? false : true)
    
    static volatile bool coex_enabled;
    
    static void coex_enable_callback(void)
    {
    	coex_enabled = true;
    }
    
    static const struct gpio_dt_spec req_spec = GPIO_DT_SPEC_GET(COEX_NODE, req_gpios);
    static const struct gpio_dt_spec pri_spec = GPIO_DT_SPEC_GET(COEX_NODE, pri_dir_gpios);
    static const struct gpio_dt_spec gra_spec = GPIO_DT_SPEC_GET(COEX_NODE, grant_gpios);
    
    static int mpsl_cx_bt_interface_3wire_config_set(void)
    {
    	nrfx_err_t err = NRFX_SUCCESS;
    	nrf_ppi_channel_t ppi_channel;
    	mpsl_coex_if_t coex_if_bt;
    	mpsl_coex_802152_3wire_gpiote_if_t *coex_if = &coex_if_bt.interfaces.coex_3wire_gpiote;
        int32_t ret;
        
        ret = gpio_pin_configure_dt(&req_spec, GPIO_OUTPUT_INACTIVE);
    	if (ret != 0) {
    		return ret;
    	}
    
    	ret = gpio_pin_configure_dt(&pri_spec, GPIO_OUTPUT_INACTIVE);
    	if (ret != 0) {
    		return ret;
    	}
    
    	ret = gpio_pin_configure_dt(&gra_spec, GPIO_INPUT | GPIO_PULL_UP);
    	if (ret != 0) {
    		return ret;
    	}
    
    	/* Allocate GPIOTE and PPI channels for the 3 lines */
        mpsl_coex_gpiote_cfg_t *gpiote_cfg[3] = {
            &(coex_if->grant_cfg),
            &(coex_if->priority_cfg),
            &(coex_if->request_cfg)
        };
        uint8_t gpio_pin[3] = {
            NRF_DT_GPIOS_TO_PSEL(COEX_NODE, grant_gpios),
            NRF_DT_GPIOS_TO_PSEL(COEX_NODE, pri_dir_gpios),
            NRF_DT_GPIOS_TO_PSEL(COEX_NODE, req_gpios),
        };
        uint8_t gpio_polar[3] = {
            MPSL_COEX_BT_GPIO_POLARITY_GET(grant_gpios),
            MPSL_COEX_BT_GPIO_POLARITY_GET(pri_dir_gpios),
            MPSL_COEX_BT_GPIO_POLARITY_GET(req_gpios),
        };
    
        for(int i = 0; i < 3; i++){
            if (nrfx_gpiote_channel_alloc(&(gpiote_cfg[i]->gpiote_ch_id)) != NRFX_SUCCESS) {
                return -ENOMEM;
            }
            if (nrfx_ppi_channel_alloc(&ppi_channel) != NRFX_SUCCESS) {
                return -ENOMEM;
            }
            gpiote_cfg[i]->gpio_pin = gpio_pin[i];
            gpiote_cfg[i]->active_high = gpio_polar[i];
            gpiote_cfg[i]->ppi_ch_id = ppi_channel;
        }
    
        /* Allocate additional PPI channel for setting the priority level at the correct time */
        /* Since Priority and Status are combined functional, it requires separate PPI channel to handle both */
        if (nrfx_ppi_channel_alloc(&ppi_channel) != NRFX_SUCCESS) {
            return -ENOMEM;
        }
        coex_if->additional_ppi_ch_id = ppi_channel;
    
        /* When the PRIORITY pin indicates the Status.*/
        /* TX is the active level */
        coex_if->is_rx_active_level = 0;
    
        /* Delay in us from the request pin is raised until the Priority and Status line shows the type of transaction (RX/TX). */
        coex_if->type_delay_us = 0;
    
        /* Delay in us from the Priority and Status line shows the type of transaction, to the radio starts its on-air activity. */
        coex_if->radio_delay_us = 50;
    
        /* Pointer to a timer instance. Timer should not be shared with any other functionality. */
        coex_if->p_timer_instance = NRF_TIMER2;
    
    
    	/* Enable support for coex APIs (make sure it's not link-time optimized out) */
    	mpsl_coex_support_802152_3wire_gpiote_if();
    
    	/* Enable 1-wire coex implementation */
    	coex_if_bt.if_id = MPSL_COEX_802152_3WIRE_GPIOTE_ID;
    	err = (int)mpsl_coex_enable(&coex_if_bt, coex_enable_callback);
        __ASSERT(err, "Failed to configure finished");
    
    	/** If enable API call is successful, wait for initialization to complete
    	 *  by waiting for the supplied callback to be called.
    	 */
    	while (!err && !coex_enabled) {
    		k_yield();
    	}
        printk("3-wire coex enabled\n");
    	return err;
    }
    
    static int mpsl_cx_init(void)
    {
    
    	return mpsl_cx_bt_interface_3wire_config_set();
    }
    
    SYS_INIT(mpsl_cx_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);

  • Hi, 

    For now, you can use the following workaround:

    • Add CONFIG_BT_LL_SOFTDEVICE_MULTIROLE=y to prj.conf - this is required as coex is not included in the peripheral library, and currently this is not correctly getting selected automatically when coex is enabled.
    • Remove the line depends on !BT as the customer has already done, and use CONFIG_MPSL_CX_THREAD=y

    The developer has tested this locally and it works on our side, note enabling the multirole library is required for coex to work. This will not build as-is on NCS latest due to a regression, but is fine on 2.5.3. Will be fixed soon and will be part of NCS 2.8.

    -Amanda H.

Reply
  • Hi, 

    For now, you can use the following workaround:

    • Add CONFIG_BT_LL_SOFTDEVICE_MULTIROLE=y to prj.conf - this is required as coex is not included in the peripheral library, and currently this is not correctly getting selected automatically when coex is enabled.
    • Remove the line depends on !BT as the customer has already done, and use CONFIG_MPSL_CX_THREAD=y

    The developer has tested this locally and it works on our side, note enabling the multirole library is required for coex to work. This will not build as-is on NCS latest due to a regression, but is fine on 2.5.3. Will be fixed soon and will be part of NCS 2.8.

    -Amanda H.

Children
  • Hello Amanda,

    That works for me. Thank you very much.

    But I have a further question:

    In `nrf/subsys/mpsl/cx/thread/mpsl_cx_thread.c:130`.

    We can see in the `request()` function that it will activate the PRIORITY pin only if the priority>127.

    The priority is a numerical value. Do we have any document about the value meaning?

    /**
     * @brief Priority of given radio operation.
     *
     * This numerical value is translated by given PTA interface driver to appropriate signal.
     * The straightforward translation would be <= UINT8_MAX/2 is low priority, while > UINT8_MAX/2
     * is high priority. More complicated PTAs support more than 2 priority levels and valid matching
     * must be implemented for such devices.
     *
     * Priority values must be aligned between all users of this API in given system. When multiple
     * radio protocols are enabled (like Bluetooth LE and IEEE 802.15.4), all protocols must use
     * aligned values (Bluetooth low priority operations must use numerically lower value than
     * IEEE 802.15.4 high priority operations).
     */
    typedef uint8_t mpsl_cx_prio_t;

    Best regards,

    Jayant

Related