This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC1352R: 2.4G/ Sub-1GHz antenna (external rf) switch control

Part Number: CC1352R
Other Parts Discussed in Thread: CC1352P, SYSCONFIG

Hi,

I've custom board based on CC1352R (rev E) - here're details of my setup:

  • dual-band, single-feed antenna, fed by XMSSJJ3G0PA-054 RF switch, controlled by DIO30
  • Software: SDK v4.20.00.35, CCS v10.0.0.00010

Question: 
I've already referred to RF antenna switch discussion (ti_drivers_config, rfDriverCallback) on forum-
posts here. So generally aware of what I need to do. Question is (actually two) - 

  1. What's the difference between rfDriverCallback and rfDriverCallbackAntennaSwitching? Do 
    I need both in my case?
  2. As I understand I need to select RF_GlobalEventInit, RF_GlobalEventRadioPowerDown, 
    RF_GlobalEventRadioSetup to Global Event Mask (in .syscfg). Which setupCommands I'm 
    suppose to process? All I need is - have DIO30 control RF switch in response to BLE(2.4G) 
    vs. Sub-1GHz bound RF driver calls; no complex "Truth table" processing routes.

Please advise. Thanks.

  • Hi,

    In general, rfDriverCallback() is a general callback to handle events for any custom or application specific behavior. rfDriverCallbackAntennaSwitching is specifically for handling antenna switching. Your application may require one or both of these functions to be implemented.

    It might be useful to look at an example that implements the rfDriverCallbackAntennaSwitching(). (You can look at something like dmm_154sensor_remote_display_app_cc1352P_2). There is also some useful comments in the ti_drivers_config.c generated by SysConfig.

    /*
     * ======== Antenna switching ========
     */
    /*
     * ======== rfDriverCallbackAntennaSwitching ========
     * Function to handle antenna switching.
     */
    void __attribute__((weak)) rfDriverCallbackAntennaSwitching(RF_Handle client, RF_GlobalEvent events, void *arg)
    {
        /* ======== PLEASE READ THIS ========
        *
        * This function is declared weak for the application to override it,
        * and the undefined function call below is intended to catch the
        * developer's attention at link time.
        * A new definition of 'rfDriverCallbackAntennaSwitching' is required.
        *
        * Please copy this function definition to create your own, but make
        * sure to remove '__attribute__((weak))' for your definition and
        * remove the below function declaration and function call.
        * 
        * To handle the events listed in '.globalEventMask', please see the
        * help text provided in 'rfDriverCallback' above. 
        * 
        * For an example on how to interact with the selected antenna pins,
        * please see the code snippet below:
        * 
        *   --- Code snippet begin ---
        * 
        * // > Initialize pins as output
        * static PIN_Handle antennaPins;
        * static PIN_State antennaState;
        * 
        * PIN_Config antennaConfig[] = {
        *   CONFIG_RF_ANTENNA_PIN_0 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MAX,
        *   PIN_TERMINATE
        * };
        * antennaPins = PIN_open(&antennaState, antennaConfig);
        *
        * // > Set pin output value manually
        * PINCC26XX_setOutputValue(CONFIG_RF_ANTENNA_PIN_0, 0); // Low
        * PINCC26XX_setOutputValue(CONFIG_RF_ANTENNA_PIN_0, 1); // High
        * 
        * // > Mux pin to be driven/controlled by the RF Core
        * // > (RFC GPIO0 is here only used as an example)
        * PINCC26XX_setMux(antennaPins, CONFIG_RF_ANTENNA_PIN_0, PINCC26XX_MUX_RFC_GPO0);
        * 
        * // > Mux pin to be controlled manually (i.e. release RF Core control)
        * PINCC26XX_setMux(antennaPins, CONFIG_RF_ANTENNA_PIN_0, PINCC26XX_MUX_GPIO);
        * 
        *   --- Code snippet end ---
        */
        extern void you_must_implement_rfDriverCallbackAntennaSwitching_see_generated_ti_drivers_config_c_in_debug_folder_or_sysconfig_preview(void);
        you_must_implement_rfDriverCallbackAntennaSwitching_see_generated_ti_drivers_config_c_in_debug_folder_or_sysconfig_preview();
    }

    In the CC1352P example, rfDriverCallbackAntennaSwitching handles RF_GlobalEventInit, RF_GlobalEventRadioPowerDown, and RF_GlobalEventRadioSetup. You won't need as complicated logic if you only have one pin for the RF switch, but the principle of the handler is similar. 

    Regards,

    Daniel

  • Thanks Daniel,

    Searching in dmm_154sensor_remote_display_app_cc1352P_2 for rfDriverCallback and rfDriverCallbackAntennaSwitching
    I see instances of these two functions only in ti_drivers_config.c and as templates (reason I'm calling them 'templates' since 
    they start with "__attribute__((weak))" which the note in ti_drivers_config says should be removed for actual function.

    So my question is when I copy those two functions (and remove __attribute__((weak))) where should they be placed? As I 
    recall, a few SDKs back (around SDK v3.4, I think) rfDriverCallback used to be called from CC1352R1_LAUNCHXL_fxns.c
    Is that where rfDriverCallback and rfDriverCallbackAntennaSwitching should be called from?

    Could you please confirm for me if this rfDriverCallbackAntennaSwitching look right for may case (single DIO30 to control
    2.4G vs Sub-1Ghz antenna: 

     * Path        DIO30
     * =========== =====
     * Off                0
     * Sub-1 GHz   1
     * 2.4 GHz       0
     */
    void rfDriverCallbackAntennaSwitching(RF_Handle client, RF_GlobalEvent events, void *arg)
    {
        /* Protect against repeated RF_init */
        static bool initialized = false;
    
        /* Local variable. */
        bool    sub1GHz   = false;
        uint8_t loDivider = 0;
    
        if (!initialized && events & RF_GlobalEventInit) {
            /* Don't do it again */
            initialized = true;
            initAntennaSwitch();
        }
        else if (events & RF_GlobalEventRadioSetup) {
            /* Switch off all paths. */
            PINCC26XX_setOutputValue(CONFIG_RF_SUB1GHZ, 0);
    
            /* Decode the generic argument as a setup command. */
            RF_RadioSetup* setupCommand = (RF_RadioSetup*)arg;
    
            switch (setupCommand->common.commandNo) {
                case (CMD_RADIO_SETUP):
                case (CMD_BLE5_RADIO_SETUP):
                        loDivider = RF_LODIVIDER_MASK & setupCommand->common.loDivider;
                        /* Sub-1GHz front-end. */
                        if (loDivider != 0) {
                            sub1GHz = true;
                        }
                        break;
                case (CMD_PROP_RADIO_DIV_SETUP):
                        loDivider = RF_LODIVIDER_MASK & setupCommand->prop_div.loDivider;
                        /* Sub-1GHz front-end. */
                        if (loDivider != 0) {
                            sub1GHz = true;
                        }
                        break;
                default:break;
            }
    
            if (sub1GHz) {
                /* Sub-1 GHz */
                /* RF core active --> Sub-1 GHz */
                PINCC26XX_setMux(antennaPins, CONFIG_RF_SUB1GHZ, PINCC26XX_MUX_GPIO);
                PINCC26XX_setOutputValue(CONFIG_RF_SUB1GHZ, 1);
            } else {
                /* 2.4 GHz */
                /* RF core active --> 2.4 GHz */
                PINCC26XX_setMux(antennaPins, CONFIG_RF_SUB1GHZ, PINCC26XX_MUX_GPIO);
                PINCC26XX_setOutputValue(CONFIG_RF_SUB1GHZ, 0);
            }
        }
        else if (events & RF_GlobalEventRadioPowerDown) {
            /* Switch off all paths. */
            PINCC26XX_setOutputValue(CONFIG_RF_SUB1GHZ, 0);
    
            /* Reset the IO multiplexer to GPIO functionality */
            PINCC26XX_setMux(antennaPins, CONFIG_RF_SUB1GHZ, PINCC26XX_MUX_GPIO);
        }
    }
    

    Best,
    SE

  • SE,

    You are correct that the functions in the generated ti_drivers_config are "templates" that should be implemented by you and placed somewhere else. It doesn't really matter where you put those functions - it's mostly an architectural decision you can make. If you want, they should be fine in your main.c file (or equivalent). Just make sure you include the proper #includes for rf.h, pin.h, etc. as needed.

    The "template" functions with __attribute__((weak)) will continue to be generated by SysConfig on each recompile but will be overrode at compile by the function you write.

    The callback function you wrote seems reasonable to me. Without your hardware, I'm not able to test though.

    Regards,

    Daniel