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.

LP-EM-CC2340R5: How to quickly and effectively scan for peripherals?

Part Number: LP-EM-CC2340R5
Other Parts Discussed in Thread: CC2340R5

Tool/software:

Hi ,

I have two LP-EM-CC2340R5 devices, one acting as a peripheral and the other as a central. The peripheral advertises every 4 seconds to save power. How should the central be configured to scan more effectively for the peripheral?

                       Peripheral settings diagram




                       Central settings diagram

                           Central  code 1-1 

/*=============================================
          AT command start scan.
=============================================*/
void start_scan(char *pdata)
{
    bStatus_t status;
    const BLEAppUtil_ScanStart_t centralScanStartParams =
    {
         /*! Zero for continuously scanning */
         .scanPeriod     = DEFAULT_SCAN_PERIOD, /* Units of 1.28sec */

         /*! Scan Duration shall be greater than to scan interval,*/
         /*! Zero continuously scanning. */
         .scanDuration   = DEFAULT_SCAN_DURATION, /* Units of 10ms */

         /*! If non-zero, the list of advertising reports will be */
         /*! generated and come with @ref GAP_EVT_SCAN_DISABLED.  */
         .maxNumReport   = APP_MAX_NUM_OF_ADV_REPORTS
    };

    status = BLEAppUtil_scanStart(&centralScanStartParams);

    if(status == FAILURE)
    {
        while(1){}
    }
}



            Central  code 1-2 (BLEAPPUTIL_ADV_REPORT)

void Central_ScanEventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
{

    uint8 pint_rssi_buf[5] = {0};


    BLEAppUtil_ScanEventData_t *scanMsg = (BLEAppUtil_ScanEventData_t *)pMsgData;
//    bleStk_GapScan_Evt_AdvRpt_t *pScanRpt = NULL;


    switch (event)
    {
        case BLEAPPUTIL_SCAN_ENABLED:
        {
            centralScanIndex = 0;
            MenuModule_printf(APP_MENU_SCAN_EVENT, 0, "Scan status: Scan started...");

            break;
        }

        case BLEAPPUTIL_SCAN_DISABLED:
        {
            uint8 i;

            for(i = 0; i < APP_MAX_NUM_OF_ADV_REPORTS; i++)
            {
                memset(&centralScanRes[i], 0, sizeof(App_scanResults));
            }

            // Go over the advertise reports that was saved in the host level and save it
            for (i = 0; i < scanMsg->pBuf->pScanDis.numReport; i++)
            {
              GapScan_Evt_AdvRpt_t advReport;
              // Get the address from the report
              GapScan_getAdvReport(i, &advReport);

              // Add the report to the scan list
              Central_addScanRes(&advReport);


            }


            UART2_write(uart, (const char *)"OK\r\n", strlen((const char *)"OK\r\n"), NULL);

            MenuModule_printf(APP_MENU_SCAN_EVENT, 0, "Scan status: Scan disabled - "
                              "Reason: " MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET
                              "Num results: " MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET,
                              scanMsg->pBuf->pScanDis.reason,
                              scanMsg->pBuf->pScanDis.numReport);
            break;
        }
        case BLEAPPUTIL_ADV_REPORT:

            pScanRpt = &scanMsg->pBuf->pAdvReport;

            //Display device name,support 20 byte(max)
            if (pScanRpt->pData != NULL)
            {
                uint8_t indx = 0;

                if(pScanRpt->dataLen > 0)
                {
                    SimpleCentral_findDeviceName(pScanRpt->pData, pScanRpt->dataLen, deviceName, MAX_SIZE);
                }
                //Determine the first byte
                if( (deviceName[0] != '\0') && (deviceName[0] <= '~') )  //if( (deviceName[0] != '\0') && (deviceName[0] >= ' ') && (deviceName[0] <= '~') )
                {
                    deviceName[MAX_SIZE-1] = '\0';
                    //RSSI
                    sprintf((char *)pint_rssi_buf, "%d",pScanRpt->rssi);

                    //print Mac address.
                    UART2_write(uart, (const char*)BLEAppUtil_convertBdAddr2Str(pScanRpt->addr),strlen((const char*)BLEAppUtil_convertBdAddr2Str(pScanRpt->addr)) , NULL);
                    UART2_write(uart, (const char *)"; ", strlen((const char *)"; "), NULL);
                    //print Device name
                    UART2_write(uart, (const char *)deviceName, strlen((const char *)deviceName), NULL);
                    UART2_write(uart, (const char *)"; ", strlen((const char *)"; "), NULL);
                    //print RSSI
                    UART2_write(uart, (const char *)pint_rssi_buf, strlen((const char *)pint_rssi_buf), NULL);

                    UART2_write(uart, (const char *)"\r\n", strlen((const char *)"\r\n"), NULL);
                }

             }

        break;

        default:
        {
            break;
        }

    }
}

  • Hello Anthony,

    Thanks for reaching out.

    Considering the scan and advertisement are not synchronized between each other, decreasing the scanning interval will decrease the chances of the scanner to find the advertiser. What I would suggest is to test by modifying the "scan period" inside the observer configurations. This parameters is used to skip a scanning event for a "period" of time in seconds. So you can start by increasing the period and measuring how much in average it takes for the scanner to find the peripheral.

    To validate that the period is taking effect, you can trace the RF output as explained here: Debugging RF Output.

    BR,

    David.

  • Hi  David,

    Thank you for your suggestion. I will share the results once I have further updates after the test.

    Regards,
    Anthony

  • Hi  David,

    I have found that if the peripheral advertising time is set too long, the Central device cannot connect even if it finds the peripheral. However, if the peripheral advertising time is set shorter, this issue does not occur. Can you provide some guidance on this? I am using basic_ble_LP_EM_CC2340R5_freertos_ticlang for the modifications.

    void Central_ScanEventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
    {
    
        uint8 pint_rssi_buf[5] = {0};
    
    
        BLEAppUtil_ScanEventData_t *scanMsg = (BLEAppUtil_ScanEventData_t *)pMsgData;
    //    bleStk_GapScan_Evt_AdvRpt_t *pScanRpt = NULL;
    
    
        switch (event)
        {
            case BLEAPPUTIL_SCAN_ENABLED:
            {
                centralScanIndex = 0;
                UART2_write(uart, (const char *)"Scan status: Scan started...\r\n", strlen((const char *)"Scan status: Scan started...\r\n"), NULL);
                MenuModule_printf(APP_MENU_SCAN_EVENT, 0, "Scan status: Scan started...");
    
                break;
            }
    
            case BLEAPPUTIL_SCAN_DISABLED:
            {
                uint8 i;
    
                for(i = 0; i < APP_MAX_NUM_OF_ADV_REPORTS; i++)
                {
                    memset(&centralScanRes[i], 0, sizeof(App_scanResults));
                }
    
                // Go over the advertise reports that was saved in the host level and save it
                for (i = 0; i < scanMsg->pBuf->pScanDis.numReport; i++)
                {
                  GapScan_Evt_AdvRpt_t advReport;
                  // Get the address from the report
                  GapScan_getAdvReport(i, &advReport);
    
                  // Add the report to the scan list
                  Central_addScanRes(&advReport);
    
    
                }
    
    
                UART2_write(uart, (const char *)"OK\r\n", strlen((const char *)"OK\r\n"), NULL);
    
                MenuModule_printf(APP_MENU_SCAN_EVENT, 0, "Scan status: Scan disabled - "
                                  "Reason: " MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET
                                  "Num results: " MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET,
                                  scanMsg->pBuf->pScanDis.reason,
                                  scanMsg->pBuf->pScanDis.numReport);
                break;
            }
            case BLEAPPUTIL_ADV_REPORT:
    
    
    
                pScanRpt = &scanMsg->pBuf->pAdvReport;
    
                //Display device name,support 20 byte(max)
                if (pScanRpt->pData != NULL)
                {
                    uint8_t indx = 0;
    
                    if(pScanRpt->dataLen > 0)
                    {
                        SimpleCentral_findDeviceName(pScanRpt->pData, pScanRpt->dataLen, deviceName, MAX_SIZE);
                    }
                    //Determine the first byte
                    if( (deviceName[0] != '\0') && (deviceName[0] >= ' ') && (deviceName[0] <= '~') ) //if( (deviceName[0] != '\0') && (deviceName[0] <= '~') )
                    {
                        deviceName[MAX_SIZE-1] = '\0';
                        //RSSI
                        sprintf((char *)pint_rssi_buf, "%d",pScanRpt->rssi);
    
                        //print Mac address.
                        UART2_write(uart, (const char*)BLEAppUtil_convertBdAddr2Str(pScanRpt->addr),strlen((const char*)BLEAppUtil_convertBdAddr2Str(pScanRpt->addr)) , NULL);
                        UART2_write(uart, (const char *)"; ", strlen((const char *)"; "), NULL);
                        //print Device name
                        UART2_write(uart, (const char *)deviceName, strlen((const char *)deviceName), NULL);
                        UART2_write(uart, (const char *)"; ", strlen((const char *)"; "), NULL);
                        //print RSSI
                        UART2_write(uart, (const char *)pint_rssi_buf, strlen((const char *)pint_rssi_buf), NULL);
    
                        UART2_write(uart, (const char *)"\r\n", strlen((const char *)"\r\n"), NULL);
                    }
    
                 }
    
            break;
    
            default:
            {
                break;
            }
    
        }
    }

    Regards,
    Anthony

  • Hello Anthony,

    Thanks for reporting back. Could you please share how the advertisement and scanning are configured? What is the advertisement interval and scanning interval, window and duration?

    What do you mean the central finds the peripheral but cannot connect? Can you see it in the list of devices to connect but when initiating a connection what happens?

    BR,

    David.

  • Hi  David,

    When I execute the AT command to start scanning, it scans for peripheral devices. My expectation is that even if it takes a long time to scan for the target device, the Central should be able to connect to the peripheral. Unfortunately, in the Central_ScanEventHandler, it seems that BLEAPPUTIL_SCAN_DISABLED does not correctly place the peripheral address found in BLEAPPUTIL_ADV_REPORT into BLEAPPUTIL_SCAN_DISABLED. This is where I am confused. After attempting to connect, it shows in the connect AT command 

    Find the target peripheral's address in BLEAPPUTIL_ADV_REPORT, but after stopping the scan, the target peripheral's address cannot be found in BLEAPPUTIL_SCAN_DISABLED.
     


    Extract the code snippet for the connect AT command.


    if(search_res == 0)
    UART2_write(uart, (const char*)"no found\r\nfail\r\n",strlen("no found\r\nfail\r\n") , NULL);






    Central syscfg


    Central start scan AT command 

    /*=============================================
              AT command start scan.
    =============================================*/
    void start_scan(char *pdata)
    {
        bStatus_t status;
        const BLEAppUtil_ScanStart_t centralScanStartParams =
        {
             /*! Zero for continuously scanning */
             .scanPeriod     = (uint16_t)DEFAULT_SCAN_PERIOD, /* Units of 1.28sec */
    
             /*! Scan Duration shall be greater than to scan interval,*/
             /*! Zero continuously scanning. */
             .scanDuration   = DEFAULT_SCAN_DURATION, /* Units of 10ms */
    
             /*! If non-zero, the list of advertising reports will be */
             /*! generated and come with @ref GAP_EVT_SCAN_DISABLED.  */
             .maxNumReport   = APP_MAX_NUM_OF_ADV_REPORTS
        };
    
        status = BLEAppUtil_scanStart(&centralScanStartParams);
    
        if(status == FAILURE)
        {
            while(1){}
        }
    }

    connect  AT command  

    /*=============================================
         AT command connect to peripheral.
    =============================================*/
    void connect_dev(char *pdata)
    {
        //Pair to device address.
        uint8_t pair_addr[15] = {0};
    
        for(uint8_t i = 0; i < 14; i++)
        {
            pair_addr[i] = pdata[10+i];
        }
    
        //============================================
        bStatus_t status;
    
        uint8_t search_res = 0;
        // Get the scan results list
        App_scanResults *appScanRes;
        uint8 size = Scan_getScanResList(&appScanRes);
    
    
        // Set the connection parameters
        BLEAppUtil_ConnectParams_t connParams =
        {
         //.peerAddrType = appScanRes->addressType,//PEER_ADDRTYPE_PUBLIC_OR_PUBLIC_ID,
         .phys = INIT_PHY_1M,
         .timeout = 10000 //1000
        };
    
    
        search_res = 0;
    
        for(uint8_t i = 0; i < size; i++)
        {
            // Convert the addresses to strings
            if(strcmp((const char *)pair_addr,(const char *)BLEAppUtil_convertBdAddr2Str(appScanRes[i].address) ) == 0)  //"0x8472933C57E4"
            {
                search_res = 1;
    //            //connect to peripheral public address.
    //            Public_dev_addr[0] = 0xE4;
    //            Public_dev_addr[1] = 0x57;
    //            Public_dev_addr[2] = 0x3C;
    //            Public_dev_addr[3] = 0x93;
    //            Public_dev_addr[4] = 0x72;
    //            Public_dev_addr[5] = 0x84;
    //
    //          // Copy the selected address
                connParams.peerAddrType = appScanRes[i].addressType;
                memcpy(connParams.pPeerAddress, appScanRes[i].address, B_ADDR_LEN);
    
                // Connect parameter.
                status = BLEAppUtil_connect(&connParams);
    
    
                if (status != SUCCESS)
                {
                    UART2_write(uart, (const char*)"Connect\r\nfail\r\n",strlen("Connect\r\nfail\r\n") , NULL);
                }
                else
                {
                    UART2_write(uart, (const char*)"Address:",strlen("Address:") , NULL);
                    UART2_write(uart, (const char*)BLEAppUtil_convertBdAddr2Str(connParams.pPeerAddress),strlen((const char*)BLEAppUtil_convertBdAddr2Str(connParams.pPeerAddress)) , NULL);
                    UART2_write(uart, (const char*)"\r\nOK\r\n",strlen("\r\nOK\r\n") , NULL);
                }
    
                break;
            }
        }
    
        //no found
        if(search_res == 0)
            UART2_write(uart, (const char*)"no found\r\nfail\r\n",strlen("no found\r\nfail\r\n") , NULL);
    
    }

    Peripheral  syscfg

    Regards,
    Anthony

  • Hello Anthony,

    How do you confirm the device has actually connected? May I ask if you subscribe to the BLEAPPUTIL_ADV_REPORT event, do you find the address you are looking for in the advertisement report. From my understanding you do find it, have you tried executing a scan disable right after finding the advertisement address in the report? I ask this because I am not sure when you are actually executing the AT command to disable the scan.

    BR,

    David.

  • Hi  David,

    I understand your point. I can only use the BLEAPPUTIL_ADV_REPORT event to inform me if there are any connectable peripheral addresses. Whether a successful connection is possible depends on the status returned by BLEAppUtil_connect(&connParams). I mentioned the connect AT command related code in the previous reply. However, in the current application, I have more than two peripherals, each advertising every 4 seconds. When the Central starts scanning for 10 seconds and then stops, I might detect one or both peripherals during that time. After scanning ends, I hope that the Central can connect to the detected peripherals at any time. Is this feasible?

    Regards,
    Anthony

  • Hello Anthony,

    I see, if you have more than two peripherals advertising with an interval of 4 seconds, then your probability of hitting the channels where the peripheral is advertising is quite low. You could: 1) Increase the advertising interval or 2) Increase the scanning window and interval (300 ms) to increase your probability of getting those adv reports.

    BR,

    David.

  • Hi  David,

    Thank you for your reply. I might need to evaluate and adjust this architecture because broadcasting every 4 seconds yields very good power consumption data for us, but it's difficult to find the peripheral and establish a connection with such a setup. This puts me in a dilemma...

    Regards,
    Anthony

  • Hello Anthony,

    Is increasing the scanning window and interval an option? Could be worth to try and see the impact on the power consumption of the central.

    BR,

    David.

  • Hi  David,


    Your suggestion is very helpful. Scanning continuously every 320ms, with the scanning window and interval parameters set to 300ms, can achieve detection within approximately 15 to 40 seconds. Sometimes it may exceed this time range, but it’s at least a good start. I will modify the code accordingly, and if there are any further updates, I will post a message here.

    Regards,
    Anthony

  • Hello Anthony,

    Glad to hear about the progress. Consider that the scanning window/interval value will depend on how many peripherals you want to effectively discover (if their adv interval is not frequent enough as in your case for power saving reasons).

    BR,

    David.

  • Hi  David,


    Listening to your suggestion to adjust the parameters and using a custom user interface, the actual results are quite good.

    Regards,
    Anthony