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

RSSI Reading

I am trying to write a program in C to have my central device(nRF52840 dongle) read the RSSI from a peripheral. I have never written C code before and was told to use: 

TASKS_RSSISTART - Start the RSSI and take one single sample of the received signal strength
TASK_RSSISTOP - Stop the RSSI measurement
RSSISAMPLE - changes due to the temperature correction factor

I have copied a few pieces of code that I found online to a file in a project in SEGGER. The code segments are displayed bellow.

I would then like to use PuTTY to read the cli example from nordic and then connect the RSSI code to the command line. 

How should I piece the code together? How should I get the code to connect to the nRF52840 dongle?

 

/*TASKS_RSSISTART - Start the RSSI and take one single sample of the receive signal strength
TASK_RSSISTOP - Stop the RSSI measurement
RSSISAMPLE - changes due to temperature correcton factor

RSSI compensation based on weather:
For TEMP ≤ -30°C, RSSISAMPLE = RSSISAMPLE +3
For TEMP > -30°C and TEMP ≤ -10°C, RSSISAMPLE = RSSISAMPLE +2
For TEMP > -10°C and TEMP ≤ +10°C, RSSISAMPLE = RSSISAMPLE +1
For TEMP > +10°C and TEMP ≤ +30°C, RSSISAMPLE = RSSISAMPLE + 0
For TEMP > +30°C and TEMP ≤ +50°C, RSSISAMPLE = RSSISAMPLE - 1
For TEMP > +50°C and TEMP ≤ +70°C, RSSISAMPLE = RSSISAMPLE - 2
For TEMP > +70°C, RSSISAMPLE = RSSISAMPLE - 3
*/

TASKS_RXEN //enable RADIO in RX mode
TASKS_START //start RADIO
TASKS_STOP //stop RADIO
TASKS_DISABLE //disable RADIO


enum nrf_radio_task_t{
      NRF_RADIO_TASK_RSSISTART=offsetof(NRF_RADIO_Type,TASKS_RSSISTART),
      NRF_RADIO_TASK_RSSISTOP = offsetof(NRF_RADIO_Type,TASKS_RSSISTOP)
}

uint rssi = (*(volatile uint32_t *)NRF_RADIO->RSSISAMPLE)  //using brute force to access register directly

if (p_gap_evt->params.adv_report.scan_rsp)
  NRF_LOG_INFO("RSSI: %d dBm",p_gap_evt->params.rssi_changed.rssi);


NRF_LOG_INFO("RSSI: %d", p_ble_evt->evt.gap_evt.params.adv_report.rssi);  //printing rssi values

Parents
  • Hi,

    If you have never program our nRF chips before I recommend you start looking at the code of one of our SDK examples to familiarize yourself with how things are done. You can download the latest SDK (version 15.30) from here.

    TASKS_RSSISTART, TASK_RSSISTOP and RSSISAMPLE are registers you can write to but I don't recommend writing to them directly. The way you are using them right now is not correct, as these are not macros or function calls, but register addresses in hardware. These addresses are usually used by higher level libraries and calls from the softdevice (our radio implementation) which you will find in our SDK (software development kit).

    Do you have a DK you can use to develop before porting your code to the dongle? Because we have a BLE CLI example for nRF52840 DK you can easily modify to give you the RSSI values when scaning for devices, but you will need to do some modifications to the code to be able to run it on the dongle so it's better if you have a nRF52840 DK available as well.

    The BLE CLI example can be found under  \nRF5_SDK_15.3.0_59ac345\examples\ble_central_and_peripheral\experimental\ble_app_interactive\pca10056

    Best regards,

    Marjeris

  • Marjeris, Thank you for your help! I will look through the examples to familiarize myself more. I only have the dongle to program directly to, so I can not use the DK to develop. I have the command line interface hooked up through putty to the dongle now and was thinking that I could change the cli interface main code to get the rssi. Is this possible? How would this work?

  • Hi,

    Yes and it's fearly easy to do as the rssi value can be parsed from the advertising data in the advertising reports, I will guide you through it:


    In 'ble_m.h' modify the struct where we save the scanned device data so we can also save the RSSI value:

    typedef struct
    {
        bool    is_not_empty;                   /**< Indicates that the structure is not empty. */
        uint8_t addr[BLE_GAP_ADDR_LEN];         /**< Device address. */
        char    dev_name[DEVICE_NAME_MAX_SIZE]; /**< Device name. */
    	int8_t  rssi;						    /**< Received Signal Strength Indication in dBm. */
    } scanned_device_t;

    In 'ble_m.c' modify the device_to_list_add() function so we also add the RSSI value to the scanned device structure when we find a new device name, since the advertising report also contains the RSSI value (see inside the ble_gap_evt_adv_report_t and you will see how the event structure or ADV report is declared), the only thing to add to the function is in line 35: m_device[idx].rssi = p_adv_report->rssi;

    static void device_to_list_add(ble_gap_evt_adv_report_t const * p_adv_report)
    {
        uint8_t  idx             = 0;
        uint16_t dev_name_offset = 0;
        uint16_t field_len;
        data_t   adv_data;
    
    
        // Initialize advertisement report for parsing
        adv_data.p_data   = (uint8_t *)p_adv_report->data.p_data;
        adv_data.data_len = p_adv_report->data.len;
    
        for ( idx = 0; idx < DEVICE_TO_FIND_MAX; idx++)
        {
            // If address is duplicated, then return.
            if (memcmp(p_adv_report->peer_addr.addr,
                       m_device[idx].addr,
                       sizeof(p_adv_report->peer_addr.addr)) == 0)
            {
                return;
            }
        }
    
        // Add device data if an empty record is found.
        for (idx = 0; idx < DEVICE_TO_FIND_MAX; idx++)
        {
            if (!m_device[idx].is_not_empty)
            {
                memcpy(m_device[idx].addr,
                       p_adv_report->peer_addr.addr,
                       sizeof(p_adv_report->peer_addr.addr));
    					
    						m_device[idx].rssi = p_adv_report->rssi;
    					
                m_device[idx].is_not_empty = true;
    
                // Search for advertising names.
                field_len = ble_advdata_search(adv_data.p_data,
                                               adv_data.data_len,
                                               &dev_name_offset,
                                               BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
    
                if (field_len == 0)
                {
                    field_len = ble_advdata_search(adv_data.p_data,
                                                   adv_data.data_len,
                                                   &dev_name_offset,
                                                   BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME);
                    // If name is not found, then return.
                    if (field_len == 0)
                    {
                        return;
                    }
                }
                memcpy(m_device[idx].dev_name, &adv_data.p_data[dev_name_offset], field_len);
                m_device[idx].dev_name[field_len] = 0;
    
                return;
            }
        }
    }

    Finally, in 'cli_m.c' modify the device_list_print function so you also print the RSSI value from p_device (your scanned device data struct):

    static void device_list_print(nrf_cli_t const * p_cli, scanned_device_t * p_device)
    {
        for (uint8_t i = 0; i < DEVICE_TO_FIND_MAX; i++)
        {
            if (p_device[i].is_not_empty)
            {
                nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Device ");
    
                char buffer[ADDR_STRING_LEN];
                int_addr_to_hex_str(buffer, BLE_GAP_ADDR_LEN, p_device[i].addr);
    
                nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "%s %s %d\n", buffer,  p_device[i].dev_name, p_device[i].rssi);
            }
        }
    }

    And that should be it.

    In the CLI terminal you will need to call command 'devices' after scaning start ( 'scan on' ) to list the device name, addresse and current RSSI value of advertising devices nearby.

    Best regards,

    Marjeris

  • Marjeris, thanks again! I went to the ble_m.h and le_m.c files through examples/ble_central/experimental/ble_app_hrs_nfc_c/ble_m.h. For the ble_m.h file, I am not exactly sure where to place my code.

     *
     */
    
    /**@brief     Application BLE module.
     *
     * @details   This module contains most of the functions used
     *            by the application to manage BLE stack events
     *            and BLE connections.
     */
    
    #ifndef BLE_M_H__
    #define BLE_M_H__
    
    #include <stdint.h>
    #include <stdbool.h>
    
    
    /**@brief Function for terminating connection with a BLE peripheral device.
     */
    void ble_disconnect(void);
    
    
    /**@brief Function for initializing the BLE stack.
     *
     * @details Initializes the SoftDevice and the BLE event interrupts.
     */
    void ble_stack_init(void);
    
    
    /**@brief Function for starting the scanning.
     */
    void scan_start(void);
    
    
    /**@brief Function for checking the connection state.
     *
     * @retval true     If peripheral device is connected.
     * @retval false    If peripheral device is not connected.
     */
    bool ble_is_connected(void);
    
    
    /**@brief Function for obtaining connection handle.
     *
     * @return Returns connection handle.
     */
    uint16_t ble_get_conn_handle(void);
    
    
    #endif // BLE_M_H__
    

    for the ble_m.c code, it looks quite a bit different than the code you have.

    static void on_adv_report(ble_gap_evt_adv_report_t const * p_adv_report)
    {
        ret_code_t  err_code;
        uint8_t   * p_adv_data;
        uint16_t    data_len;
        uint16_t    field_len;
        uint16_t    dev_name_offset = 0;
        char        dev_name[DEV_NAME_LEN];
    
        // Initialize advertisement report for parsing.
        p_adv_data = (uint8_t *)p_adv_report->data.p_data;
        data_len   = p_adv_report->data.len;
    
        // Search for advertising names.
        field_len = ble_advdata_search(p_adv_data, 
                                       data_len, 
                                       &dev_name_offset, 
                                       BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
        if (field_len == 0)
        {
            // Look for the short local name if it was not found as complete.
            field_len = ble_advdata_search(p_adv_data, 
                                           data_len,
                                           &dev_name_offset,
                                           BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME);
            if (field_len == 0)
            {
                // Exit if the data cannot be parsed.
                return;
            }
        }
    
        memcpy(dev_name, &p_adv_data[dev_name_offset], field_len);
        dev_name[field_len] = 0;
    
        NRF_LOG_DEBUG("Found advertising device: %s", nrf_log_push((char *)dev_name));
    
     

    Another problem that I have found is that when using SEGGER to develope, I can not compile code to the dongle and the project sizes are to big when trying keil. What IDE do you suggest using? Should I use a GNU?

Reply
  • Marjeris, thanks again! I went to the ble_m.h and le_m.c files through examples/ble_central/experimental/ble_app_hrs_nfc_c/ble_m.h. For the ble_m.h file, I am not exactly sure where to place my code.

     *
     */
    
    /**@brief     Application BLE module.
     *
     * @details   This module contains most of the functions used
     *            by the application to manage BLE stack events
     *            and BLE connections.
     */
    
    #ifndef BLE_M_H__
    #define BLE_M_H__
    
    #include <stdint.h>
    #include <stdbool.h>
    
    
    /**@brief Function for terminating connection with a BLE peripheral device.
     */
    void ble_disconnect(void);
    
    
    /**@brief Function for initializing the BLE stack.
     *
     * @details Initializes the SoftDevice and the BLE event interrupts.
     */
    void ble_stack_init(void);
    
    
    /**@brief Function for starting the scanning.
     */
    void scan_start(void);
    
    
    /**@brief Function for checking the connection state.
     *
     * @retval true     If peripheral device is connected.
     * @retval false    If peripheral device is not connected.
     */
    bool ble_is_connected(void);
    
    
    /**@brief Function for obtaining connection handle.
     *
     * @return Returns connection handle.
     */
    uint16_t ble_get_conn_handle(void);
    
    
    #endif // BLE_M_H__
    

    for the ble_m.c code, it looks quite a bit different than the code you have.

    static void on_adv_report(ble_gap_evt_adv_report_t const * p_adv_report)
    {
        ret_code_t  err_code;
        uint8_t   * p_adv_data;
        uint16_t    data_len;
        uint16_t    field_len;
        uint16_t    dev_name_offset = 0;
        char        dev_name[DEV_NAME_LEN];
    
        // Initialize advertisement report for parsing.
        p_adv_data = (uint8_t *)p_adv_report->data.p_data;
        data_len   = p_adv_report->data.len;
    
        // Search for advertising names.
        field_len = ble_advdata_search(p_adv_data, 
                                       data_len, 
                                       &dev_name_offset, 
                                       BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME);
        if (field_len == 0)
        {
            // Look for the short local name if it was not found as complete.
            field_len = ble_advdata_search(p_adv_data, 
                                           data_len,
                                           &dev_name_offset,
                                           BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME);
            if (field_len == 0)
            {
                // Exit if the data cannot be parsed.
                return;
            }
        }
    
        memcpy(dev_name, &p_adv_data[dev_name_offset], field_len);
        dev_name[field_len] = 0;
    
        NRF_LOG_DEBUG("Found advertising device: %s", nrf_log_push((char *)dev_name));
    
     

    Another problem that I have found is that when using SEGGER to develope, I can not compile code to the dongle and the project sizes are to big when trying keil. What IDE do you suggest using? Should I use a GNU?

Children
  • Hi,

    You should modify the files inside the CLI example, which is located in examples\ble_central_and_peripheral\experimental\ble_app_interactive
    Right now you are modifying files from another example, so that's why they look so different...

    ella482 said:
    I have the command line interface hooked up through putty to the dongle now and was thinking that I could change the cli interface main code to get the rssi. Is this possible? How would this work?

    I think I misunderstood you. I though you already had tested the CLI example and modified it to work with the dongle.

    The documentation for the CLI example is located here. But the thing is, this example comes only for two boards: pca10040 which is the nRF52832 DK and pca10056 which is the nRF52840 DK, which uses the same chip as the nRF52840 dongle.

    You will need to modify the pca10056 example to work together with the dongle, what you will need to do is to change the CLI backend to use USB-CDC instead of UART and change the board definition to pca10059 (which is the name of the nrf52840 dongle).

    My recommendation is to get your hands in a nrf52840 DK so you can familiarize yourself with the way nRF programming works and with the CLI example before porting it to the dongle.

    I recommend using Segger to build an develop the project, because if the project is too big you will not be able build it using the free version of Keil. But you cannot use Segger/Keil to upload any firmware to the dongle. If you want to upload a custom firmware to the dongle, you need to use the nRF Connect for Desktop programmer app. Segger/Keil uses J-Link to program the DK, but since the dongle doesn't have a J-Link interface so that's why you will not be able to program them using Segger/Keil.

    There is a tutorial on how to program the nRF52840 dongle here: https://devzone.nordicsemi.com/nordic/short-range-guides/b/getting-started/posts/nrf52840-dongle-programming-tutorial

    Best regards,

    Marjeris

  • Marjeris, 

    Thank you! I was using the cli example from peripheral and not BLE. I will change the files to the ble_app_interactive now. How should I change the hex files once my code is changed, so that I can program with the desktop programmer? In the documentation for the CLI, it just states compile code onto the board.

    Ella

  • Hi,

    You don't need to make any changes to the hex file after building your code. If you are using segger to build the project you will find the project hex file under ses/output/release/exe/ble_app_interactive_s140_pca10056.hex

    Using the nRF connect programmer app you should flash both this hex file and the corresponding softdevice -> components\softdevie\s140\hex\s140_nrf52_6.1.1_softdevice.hex

    I recommend testing the programmer app using another example and familiarize yourself with how it works. You can try to build the blinky example located in examples\ble_peripheral\ble_app_blinky\pca10059\s140\ses\ble_app_blinky_pca10059_s140.emProject and flash it together with the softdevice to the dongle using the programmer app.

    Best regards,

    Marjeris

Related