This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Status and approach for PA/LNA Support in BLE/Thread Concurrent Multiprotocol

I am migrating to the Fanstel BT840XE module with nRF52840 and a Skyworks PA/LNA.  I need some assistance in getting my PA/LNA working in a multiprotocol setup. 

I have successfully implemented and tested the Softdevice portion of PA/LNA control for BLE, and tested it on my custom hardware platform.  I confirmed operation using a BLE-only example from the SDK and confirmed the transmit power is indeed higher when the PA/LNA flag is set -- I think this demonstrates my code is correct and hardware is working.

My actual multiprotocol project implements the same BLE PA/LNA setup tested above (code snippets below).  I have *not yet* implemented any PA/LNA control for Thread.

1. At this point, I would expect my BLE advertisements would be send with higher power with the PA/LNA enabled, but they are not.  Is the multiprotocol usage somehow defeating the PA/LNA initialization I am doing?

2. What is the recommended approach to PA/LNA in a BLE/Thread multiprotocol concurrent project?

DETAILS:

My project uses concurrent BLE/Thread Multiprotocol with nRF5_SDK_for_Thread_and_Zigbee_3.1.0_c7c4730 and S140 6.1.1.

My custom board file includes the following section for PA/LNA and transmit power:

#define APP_PA_LNA
// This board has a Power Amplifier and LNA  "APP_PA_LNA" will trigger main to initialize it.
#ifdef APP_PA_LNA
#define APP_PA_PIN      17
#define APP_LNA_PIN     19
#define APP_CHL_PIN	8
#define APP_CPS_PIN	6
#endif //APP_PA_LNA

#define MAX_BLE_XMIT_PWR_DBM  0   //Fanstel BT840XE max transmit power from radio IC is +2dBm.  PA adds 21dBm!  Use with 0dBm gain antenna max for FCC/IC.
#define THREAD_POWER 0    // <i> Transmit Power (in dBm) used by Thread.

In main, after softdevice init, I configure the PA/LNA:

    ble_stack_init();

    // set up PA/LNA if present - NOTE: must be done after softdevice is enabled.
    #ifdef APP_PA_LNA	
	nrf_gpio_cfg_output(APP_CPS_PIN);
	nrf_gpio_cfg_output(APP_CHL_PIN);
	nrf_gpio_pin_set(APP_CHL_PIN);
	nrf_gpio_pin_clear(APP_CPS_PIN); //enable
	pa_lna_init(APP_PA_PIN,APP_LNA_PIN);
    #endif	

Here is my PA/LNA init code:

#include "fanstel_pa_lna.h"
#include "nrf_assert.h"
#include "nrf_log.h"
#include "ble.h"
#include "app_error.h"
#include "nrf_drv_gpiote.h"
#include "nrf_drv_ppi.h"

void pa_lna_init(uint32_t gpio_pa_pin, uint32_t gpio_lna_pin)
{
    ble_opt_t opt;
    uint32_t gpiote_ch = NULL;
    ret_code_t err_code;        

    memset(&opt, 0, sizeof(ble_opt_t));
    
    err_code = nrf_drv_gpiote_init();
    if(err_code != NRF_ERROR_INVALID_STATE)
        APP_ERROR_CHECK(err_code);
    
    err_code = nrf_drv_ppi_init();
    //if(err_code != MODULE_ALREADY_INITIALIZED)
        APP_ERROR_CHECK(err_code);
    
    nrf_ppi_channel_t ppi_set_ch;
    nrf_ppi_channel_t ppi_clr_ch;
    
    err_code = nrf_drv_ppi_channel_alloc(&ppi_set_ch);
    APP_ERROR_CHECK(err_code);
    
    err_code = nrf_drv_ppi_channel_alloc(&ppi_clr_ch);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
    
    if((gpio_pa_pin == NULL) && (gpio_lna_pin == NULL))
    {
        err_code = NRF_ERROR_INVALID_PARAM;
        APP_ERROR_CHECK(err_code);
    }    

    if(gpio_pa_pin != NULL)
    {
        if(gpiote_ch == NULL)
        {
            err_code = nrf_drv_gpiote_out_init(gpio_pa_pin, &config);
            APP_ERROR_CHECK(err_code);
            
            gpiote_ch = nrf_drv_gpiote_out_task_addr_get(gpio_pa_pin); 
        }
        
        // PA config
        opt.common_opt.pa_lna.pa_cfg.active_high = 1;   // Set the pin to be active high
        opt.common_opt.pa_lna.pa_cfg.enable      = 1;   // Enable toggling
        opt.common_opt.pa_lna.pa_cfg.gpio_pin    = gpio_pa_pin; // The GPIO pin to toggle tx  
    }
    
    if(gpio_lna_pin != NULL)
    {
        if(gpiote_ch == NULL)
        {
            err_code = nrf_drv_gpiote_out_init(gpio_lna_pin, &config);
            APP_ERROR_CHECK(err_code);        
            
            gpiote_ch = nrf_drv_gpiote_out_task_addr_get(gpio_lna_pin); 
        }
        
        // LNA config
        opt.common_opt.pa_lna.lna_cfg.active_high  = 1; // Set the pin to be active high
        opt.common_opt.pa_lna.lna_cfg.enable       = 1; // Enable toggling
        opt.common_opt.pa_lna.lna_cfg.gpio_pin     = gpio_lna_pin;  // The GPIO pin to toggle rx
    }

    // Common PA/LNA config
    opt.common_opt.pa_lna.gpiote_ch_id  = (gpiote_ch - NRF_GPIOTE_BASE) >> 2;   // GPIOTE channel used for radio pin toggling
    opt.common_opt.pa_lna.ppi_ch_id_clr = ppi_clr_ch;   // PPI channel used for radio pin clearing
    opt.common_opt.pa_lna.ppi_ch_id_set = ppi_set_ch;   // PPI channel used for radio pin setting
    
    err_code = sd_ble_opt_set(BLE_COMMON_OPT_PA_LNA, &opt);
    APP_ERROR_CHECK(err_code);
        
    if (err_code == NRF_SUCCESS)
    {
        NRF_LOG_INFO("PA/LNA Successfully Enabled");
    }
    return;
}

When I start advertising, I set the radio transmit power using the power level defined in the board file:

#define BLE_GAP_ADV_POWER               MAX_BLE_XMIT_PWR_DBM                    /**< BLE Transmit power to use for advertising, in dBm. */

/**@brief Function for starting advertising.
 */
static void advertising_start(void)
{
    ret_code_t err_code;

    // NORDIC: SET TX POWER FOR ADVERTISING
    err_code = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, m_advertising.adv_handle, BLE_GAP_ADV_POWER); 
    APP_ERROR_CHECK(err_code); 
    
    err_code = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
    // We don't have a good way of knowing current adv state, so ignore the error
    if ((err_code != NRF_SUCCESS) )  //&& (err_code != NRF_ERROR_INVALID_STATE))
    {
        APP_ERROR_CHECK(err_code);
    }

    NRF_LOG_INFO("advertising is started");
}

Parents Reply Children
No Data
Related