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

nRF52840 DK- Softdevice events handling

Hello :

I come from STM32 programming and I am new to Nordic device programming.

for nRF52840 DK, I am looking at the ble-blinking example and try to understand Softdevice event handling process flow.

I understand when a Softdevice has an event, it will trigger an interrupt and the interrupt service routine will execute the 

 nrf_sdh_evts_poll().

 However,

I am not sure how the above  evts-poll function will call the    -- ble_evt_handler     and the            ble_lbs_on_ble_evt ?  ( LED control) 

How does the nrf_sdh_evts_poll() know the address of  ble_evt_handler          and the             ble_lbs_on_ble_evt ? ( LED control) 

There are some discussion saying the event handles are registered , so nrf_sdh_evts_poll()  will know which handle to execute ?

Could you explain it in details ?  ( event handling registration  process ,  etc?)

I would like to understand how the Softdevice event handling  works.

Thanks a lot !

 

ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)

 ble_lbs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)

void nrf_sdh_evts_poll(void)
{
nrf_section_iter_t iter;

// Notify observers about pending SoftDevice event.
for (nrf_section_iter_init(&iter, &sdh_stack_observers);
nrf_section_iter_get(&iter) != NULL;
nrf_section_iter_next(&iter))
{
nrf_sdh_stack_observer_t * p_observer;
nrf_sdh_stack_evt_handler_t handler;

p_observer = (nrf_sdh_stack_observer_t *) nrf_section_iter_get(&iter);
handler = p_observer->handler;

handler(p_observer->p_context);
}
}

Parents
  • HI Acamp

    The SoftDevice uses the EGU(Event Generator Unit) to generate a software interrupt to notify the application about BLE and SOC events. So both SoC and BLE events from the SoftDevice are signaled through SWI2_EGU2_IRQHandler, here sdh_evts_poll() is called which in turns notifies all observers registered through the NRF_SDH_STACK_OBSERVER() macro, i.e. nrf_sdh_ble_evts_poll() and nrf_sdh_soc_evts_poll(). These functions will in turn notify all the observers registered through the NRF_SDH_BLE_OBSERVER() and NRF_SDH_SOC_OBSERVER() macros.

    So when an observer ( i.e. an event handler ) is registered through the NRF_SDH_BLE_OBSERVER or NRF_SDH_SOC_OBSERVER macros, then the function pointer to the event handler is stored in a specific section in flash. The nrf_sdh_soc_evts_poll() and nrf_sdh_ble_evts_poll() functions will iterate through this section and call the handler functions through the function pointers stored in the section. This section will also be ordered depending on which priority that was assigned to the handler. 

    Lets take a practical example, in the ble_app_hrs example you'll see the following macro at the top of main.c.

    BLE_HRS_DEF(m_hrs);  

    Going to the definition, we see that this macro registers the ble_hrs_on_ble_evt() function as the handler and assign it BLE_HRS_BLE_OBSERVER_PRIO (its set to 2) as the priority. The BLE_HRS_BLE_OBSERVER_PRIO  priority is set in the sdk_config.h file 

    #define BLE_HRS_DEF(_name)                                                                          \
    static ble_hrs_t _name;                                                                             \
    NRF_SDH_BLE_OBSERVER(_name ## _obs,                                                                 \
                         BLE_HRS_BLE_OBSERVER_PRIO,                                                     \
                         ble_hrs_on_ble_evt, &_name)

    If we look at ble_stack_init() in the same example, we see that it registers ble_evt_handler() as the handler function with priority APP_BLE_OBSERVER_PRIO( which is set to 3). 

    static void ble_stack_init(void)
    {
        ret_code_t err_code;
    
        err_code = nrf_sdh_enable_request();
        APP_ERROR_CHECK(err_code);
    
        // Configure the BLE stack using the default settings.
        // Fetch the start address of the application RAM.
        uint32_t ram_start = 0;
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Enable BLE stack.
        err_code = nrf_sdh_ble_enable(&ram_start);
        APP_ERROR_CHECK(err_code);
    
        // Register a handler for BLE events.
        NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }
    

    So whenever a BLE event is signaled by the SoftDevice, then the call stack will roughly be like this SWI2_EGU2_IRQHandler -> nrf_sdh_ble_evts_poll() -> ble_hrs_on_ble_evt -> ble_evt_handler. So ble_hrs_on_ble_evt will be called first by nrf_sdh_ble_evts_poll as it has a higher priority than ble_evt_handler. 

    I hope that clarifies it. If not, then just post additional question in comments. 

    Best regards

    Bjørn

  • That makes great sense to me.

    I do have a follow up question.

    For ble_app_blinky example, "  nRF5SDK160098a08e2\examples\ble_peripheral\ble_app_blinky\pca10056\s140\ses "

    Now, I understand ble_evt_handler is registered through NRF_SDH_BLE_OBSERVER.

    My question is about: How the LED write function get executed from smartphone to Softdevice  event and then to application code " on_write () "?

    Looks like LED write event handle is registered through sd_ble_gatts_service_add( )  API?

    Beside NRF_SDH_BLE_OBSERVER, we can also register an event handle by sd_ble_gatts_service_add( )  API ?

    Thanks a lot !

    static void on_write(ble_lbs_t * p_lbs, ble_evt_t const * p_ble_evt)

    void ble_lbs_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)

    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_lbs->service_handle);

  • I think I figure it out.

    There is    macro        BLE_LBS_DEF(m_lbs);     in main ()  file

    Thanks

Reply Children
Related