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

nRF51822 ADC and S110

Hi, I am new to BLE development and I am currently using nRF51822 with the soft device S110. I am using the example ble_app_hrs that includes the ADC converter. I would like advertise the analog data (from pin 2) and be able to see it on the Master Control Panel. What part of the code do I need to modify to advertise the data. So far the example is just sending the heart rate and battery level.

Thank you for the help.

  • Hi

    If I understand you correctly you want to show your ADC value in the advertising packet instead of (or in addition to) in a service?

    To show your ADC value in the advertising packet you can use the manufacturer specific field in. You can do this by modifying your advertising_init() function to something like this:

    static void advertising_init(void)
    {
        uint32_t      err_code;
        // NORDIC. Moved some variables to make them accessible in all functions
        uint8_t       flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    
        ble_uuid_t adv_uuids[] =
        {
            {BLE_UUID_HEART_RATE_SERVICE,         BLE_UUID_TYPE_BLE},
            {BLE_UUID_BATTERY_SERVICE,            BLE_UUID_TYPE_BLE},
            {BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE}
        };
    
        // NORDIC Prepare the Manufacturer specific data packet
        adc_data.company_identifier           = 0x0059; // Nordics company ID
        adc_data.data.p_data                  = &adc;
        adc_data.data.size                    = sizeof(adc);
        
        // Build and set advertising data.
        memset(&advdata, 0, sizeof(advdata));
    
        advdata.name_type               = BLE_ADVDATA_FULL_NAME;
        advdata.include_appearance      = true;
        advdata.flags.size              = sizeof(flags);
        advdata.flags.p_data            = &flags;
        advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
        advdata.uuids_complete.p_uuids  = adv_uuids;
        // NORDIC add Manufacturer specific data packet
        advdata.p_manuf_specific_data   = &adc_data;  
    
        err_code = ble_advdata_set(&advdata, NULL);
        APP_ERROR_CHECK(err_code);
    
        // Initialize advertising parameters (used when starting advertising).
        memset(&m_adv_params, 0, sizeof(m_adv_params));
    
        m_adv_params.type        = BLE_GAP_ADV_TYPE_ADV_IND;
        m_adv_params.p_peer_addr = NULL;                           // Undirected advertisement.
        m_adv_params.fp          = BLE_GAP_ADV_FP_ANY;
        m_adv_params.interval    = APP_ADV_INTERVAL;
        m_adv_params.timeout     = APP_ADV_TIMEOUT_IN_SECONDS;
    }
    

    Now you need to update your adc values. I found a quick and dirty solution by just modifying the ADC_IRQHandler(void) to update the adc value:

    void ADC_IRQHandler(void)
    {
        /* Clear dataready event */
        NRF_ADC->EVENTS_END = 0;	
        // NORDIC adc value is updated here
        adc = NRF_ADC->RESULT; 
        nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT2, adc); /* Write ADC result to port 2 */
        nrf_gpio_pin_toggle(LED_1);
        NRF_ADC->TASKS_STOP = 1;//Use the STOP task to save current. Workaround for PAN_028 rev1.5 anomaly 1.
        sd_clock_hfclk_release();//Release the external crystal
    }	
    

    and then I simply updated the ADC value in the advertising packet in battery_level_meas_timeout_handler():

    static void battery_level_meas_timeout_handler(void * p_context)
    {
        UNUSED_PARAMETER(p_context);
        battery_level_update();
    
        // NORDIC reinitate the complete advertising. Just copy paste the code form advertise_init() and update the adc value
        uint32_t err_code;
        uint8_t       flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
        ble_uuid_t adv_uuids[] =
        {
            {BLE_UUID_HEART_RATE_SERVICE,         BLE_UUID_TYPE_BLE},
            {BLE_UUID_BATTERY_SERVICE,            BLE_UUID_TYPE_BLE},
            {BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE}
        };
        adc_data.company_identifier           = 0x0059; // Nordics company ID
        adc_data.data.p_data                  = &adc;
        adc_data.data.size                    = sizeof(adc);
        
        // Build and set advertising data.
        memset(&advdata, 0, sizeof(advdata));
    
        advdata.name_type               = BLE_ADVDATA_FULL_NAME;
        advdata.include_appearance      = true;
        advdata.flags.size              = sizeof(flags);
        advdata.flags.p_data            = &flags;
        advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
        advdata.uuids_complete.p_uuids  = adv_uuids;
        // NORDIC add adc value to data packet
        advdata.p_manuf_specific_data   = &adc_data;  
    
        err_code = ble_advdata_set(&advdata, NULL);
        APP_ERROR_CHECK(err_code);
    }
    

    I have attached my main.c file. It should be copy paste-able into your example code. You can search for "NORDIC" and find all my modifications. main.c

  • Thank you so much for the sample code. I was able to use it. My only question is that now that I am advertising the ADC data shouldn't I be able to see it on the Master Control Panel under the Battery Level Value ? The value shown on the Batter Level Value is still the one as before and not the ADC value. Does't advertising mean that is sending the data and the Master Control Panel be able to read it ?

    Thank you for the help.

  • This was just meant to be a very quick example on how to advertise a variable value. It doesn't really have anything to do with the battery level other than timing. In other words, the ADC values will be updated and stored in your advertising packet every time the (simulated) battery value is updated. I only did this so I didn't have to create a new timer and to save time.

Related