softdevice和应用程序之间的交互

一 softdevice介绍

在这里插入图片描述
softdevice是预先编译好的二进制文件,被烧录在0地址处。softdevice是通过SVC中断和软中断来实现与应用程序交互的。

一 应用程序调用softdevice中的方法

应用程序通过SV calls调用softdevice中的方法。
在这里插入图片描述

SVC、事件和选项编号被分成每个 API 模块的子范围。 每个模块接收其整个分配的 SVC 调用范围,无论是否实现,但对于在其范围内未实现或未定义的调用返回 BLE_ERROR_NOT_SUPPORTED。

使用连接函数来说明SVC的过程。

SVCALL(SD_BLE_GAP_CONNECT, uint32_t, sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params, ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag));

  • 用户调用sd_ble_gap_connect函数,异常号为SD_BLE_GAP_CONNECT (0x8B)
  • 产生异常,CPU开始执行该异常号对应的回调函数,该函数在协议栈实现。
  • 由于nordic的svc是非阻塞的,因此svc的调用会很快返回。

每一个softdevice API对应一个SVC异常号(softdevice API是非阻塞的),也就是说,每当应用程序调用softdevice API,其实是产生一个SVC异常,然后进入到softdevice协议栈,由softdevice的SVC handler进行相应处理。

二 softdevice向应用程序发送通知

当系统有事件需要上报给应用程序时,softdevice通过SWI(软中断)通知应用程序。软中断其实就是IRQ(外部中断)的一种,只不过是用软件来触发的。
在这里插入图片描述

SWI实际上就是一个中断。
在这里插入图片描述
在arm_startup_nrf52833.s中定义了中断处理函数,SWI2_EGU2_IRQHandler
在这里插入图片描述

nrf51_to_nrf52.h

#ifndef SWI2_IRQHandler
    #define SWI2_IRQHandler         SWI2_EGU2_IRQHandler
#endif

nrf_soc.h

#define SD_EVT_IRQHandler                 (SWI2_IRQHandler)  /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events.
                                                                       The default interrupt priority for this handler is set to 6 */

经过上述的重定义,SWI2_EGU2_IRQHandler的名字最终被定义成了SD_EVT_IRQHandler,该函数在nrf_sdh.c中实现。

nrf_sdh.c


/*
#define NRF_SDH_STACK_OBSERVER_PRIO_LEVELS 2
NRF_SECTION_SET_DEF 这个宏定义非常的复杂,简单点来讲就是在在flash中开辟一个空间,空间大小为 NRF_SDH_STACK_OBSERVER_PRIO_LEVELS(个数) 乘 nrf_sdh_stack_observer_t(单个元素大小)
NRF_SDH_STACK_OBSERVER_PRIO_LEVELS开辟空间的个数, nrf_sdh_stack_observer_t为数据类型。
一共NRF_SDH_STACK_OBSERVER_PRIO_LEVELS个段,每个段都有一个索引名字。
sdh_stack_observers(i), 其中i的取值范围 [0, NRF_SDH_STACK_OBSERVER_PRIO_LEVELS), 真正的名字不包括小括号。比如sdh_stack_observers0, sdh_stack_observers1
后面详细分析这个宏定义。
*/
NRF_SECTION_SET_DEF(sdh_stack_observers, nrf_sdh_stack_observer_t, NRF_SDH_STACK_OBSERVER_PRIO_LEVELS);

void SD_EVT_IRQHandler(void)
{
    nrf_sdh_evts_poll();
}

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);
    }
}

当softdevice有事件需要通知应用层的时候,会通过软件产生一个中断(SWI),把事件的类型和参数放进应用层的事件队列中,然后返回。

应用程序通过注册一个监听函数,来监听协议栈的发出来的事件。
nrf_sdh_ble.c


// 跟nrf_sdh.c中的宏一样,在flash中开辟空间。应用程序通过NRF_SDH_BLE_OBSERVER 向 sdh_ble_observers 进行注册监听
NRF_SECTION_SET_DEF(sdh_ble_observers, nrf_sdh_ble_evt_observer_t, NRF_SDH_BLE_OBSERVER_PRIO_LEVELS);

/*
这个宏定义实际上就是一个监听者,用来监听sdh_stack_observers发布的消息。
*/
NRF_SDH_STACK_OBSERVER(m_nrf_sdh_ble_evts_poll, NRF_SDH_BLE_STACK_OBSERVER_PRIO) =
{
    .handler   = nrf_sdh_ble_evts_poll,
    .p_context = NULL,
};


//ble事件的分发
static void nrf_sdh_ble_evts_poll(void * p_context)
{
    UNUSED_VARIABLE(p_context);

    ret_code_t ret_code;

    if (!m_stack_is_enabled)
    {
        return;
    }

    while (true)
    {
        /*lint -save -e(587) */
        __ALIGN(4) uint8_t evt_buffer[NRF_SDH_BLE_EVT_BUF_SIZE];
        /*lint -restore */

        ble_evt_t * p_ble_evt;
        uint16_t    evt_len = (uint16_t)sizeof(evt_buffer);

        ret_code = sd_ble_evt_get(evt_buffer, &evt_len);
        if (ret_code != NRF_SUCCESS)
        {
            break;
        }

        p_ble_evt = (ble_evt_t *)evt_buffer;

        NRF_LOG_DEBUG("BLE event: 0x%x.", p_ble_evt->header.evt_id);

        // Forward the event to BLE observers.
        nrf_section_iter_t  iter;
        for (nrf_section_iter_init(&iter, &sdh_ble_observers);
             nrf_section_iter_get(&iter) != NULL;
             nrf_section_iter_next(&iter))
        {
            nrf_sdh_ble_evt_observer_t * p_observer;
            nrf_sdh_ble_evt_handler_t    handler;

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

            handler(p_ble_evt, p_observer->p_context);
        }
    }

    if (ret_code != NRF_ERROR_NOT_FOUND)
    {
        APP_ERROR_HANDLER(ret_code);
    }
}

main.c

//监听BLE的事件,对应的通知者是sdh_ble_observers
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);

三 分析两个重要的宏定义

这里以ble为例。

1. NRF_SECTION_SET_DEF

NRF_SECTION_SET_DEF(sdh_ble_observers, nrf_sdh_ble_evt_observer_t, NRF_SDH_BLE_OBSERVER_PRIO_LEVELS);

在这里插入图片描述
在这里插入图片描述

在map文件中产生一个sdh_ble_observers 数组, sdh_ble_observers0, sdh_ble_observers1, sdh_ble_observers2, sdh_ble_observers3,sdh_ble_observers3在当前代码中没有用到。
sdh_ble_observers0$ $ Base表示段起始地址,sdh_ble_observers0$ $Limit表示段结束地址

  1. 第一次展开

替换变量

MACRO_REPEAT_FOR(4, NRF_SECTION_DEF_, sdh_ble_observers, nrf_sdh_ble_evt_observer_t)
static nrf_section_t const CONCAT_2(sdh_ble_observers, _array)[] =                                              \
{                                                                                                   \
    MACRO_REPEAT_FOR(4, NRF_SECTION_SET_DEF_, sdh_ble_observers)                                           \
};                                                                                                  \
/*lint -restore */                                                                                  \
static nrf_section_set_t const sdh_ble_observers =                                                              \
{                                                                                                   \
    .p_first   = CONCAT_2(sdh_ble_observers, _array),                                                           \
    .p_last    = CONCAT_2(sdh_ble_observers, _array) + ARRAY_SIZE(CONCAT_2(sdh_ble_observers, _array)),                     \
    .item_size = sizeof(nrf_sdh_ble_evt_observer_t),                                                                     \
}
  1. 第二次展开

展开MACRO_REPEAT_FOR和CONCAT_2

MACRO_REPEAT_FOR_4((0,...32), NRF_SECTION_DEF_, sdh_ble_observers, nrf_sdh_ble_evt_observer_t)
static nrf_section_t const sdh_ble_observers_array[] =                                              \
{                                                                                                   \
	MACRO_REPEAT_FOR_4((0,...32), NRF_SECTION_SET_DEF_, sdh_ble_observers)
}; 
static nrf_section_set_t const sdh_ble_observers =                                                              \
{                                                                                                   \
    .p_first   = sdh_ble_observers_array,                                                           \
    .p_last    = sdh_ble_observers_array + ARRAY_SIZE(sdh_ble_observers_array),                     \
    .item_size = sizeof(nrf_sdh_ble_evt_observer_t),                                                                     \
}
  1. 第三次展开

展开MACRO_REPEAT_FOR_4

NRF_SECTION_DEF_(0, sdh_ble_observers, nrf_sdh_ble_evt_observer_t)
NRF_SECTION_DEF_(1, sdh_ble_observers, nrf_sdh_ble_evt_observer_t)
NRF_SECTION_DEF_(2, sdh_ble_observers, nrf_sdh_ble_evt_observer_t)
NRF_SECTION_DEF_(3, sdh_ble_observers, nrf_sdh_ble_evt_observer_t)
static nrf_section_t const sdh_ble_observers_array[] = {
	NRF_SECTION_SET_DEF_(0, sdh_ble_observers)
	NRF_SECTION_SET_DEF_(1, sdh_ble_observers)
	NRF_SECTION_SET_DEF_(2, sdh_ble_observers)
	NRF_SECTION_SET_DEF_(3, sdh_ble_observers)
}
static nrf_section_set_t const sdh_ble_observers =                                                   
{                                                                                                   
    .p_first   = sdh_ble_observers_array,                                                           
    .p_last    = sdh_ble_observers_array + ARRAY_SIZE(sdh_ble_observers_array),                     
    .item_size = sizeof(nrf_sdh_ble_evt_observer_t),                                                 
}
  1. 第四次展开
    展开NRF_SECTION_DEF_ 和 NRF_SECTION_SET_DEF_
extern nrf_sdh_ble_evt_observer_t* sdh_ble_observers0$$Base;          
extern void      * sdh_ble_observers0$$Limit;
extern nrf_sdh_ble_evt_observer_t* sdh_ble_observers1$$Base;          
extern void      * sdh_ble_observers1$$Limit;
extern nrf_sdh_ble_evt_observer_t* sdh_ble_observers2$$Base;          
extern void      * sdh_ble_observers2$$Limit;
extern nrf_sdh_ble_evt_observer_t* sdh_ble_observers3$$Base;          
extern void      * sdh_ble_observers3$$Limit;

static nrf_section_t const sdh_ble_observers_array[] = {
	{                                                                                                   
    	.p_start = &sdh_ble_observers0$$Base,                                  
    	.p_end   = &sdh_ble_observers0$$Limit,                                    
	},
	{                                                                                                   
    	.p_start = &sdh_ble_observers1$$Base,                                  
    	.p_end   = &sdh_ble_observers1$$Limit,                                    
	},
	{                                                                                                   
    	.p_start = &sdh_ble_observers2$$Base,                                  
    	.p_end   = &sdh_ble_observers2$$Limit,                                    
	},
	{                                                                                                   
    	.p_start = &sdh_ble_observers3$$Base,                                  
    	.p_end   = &sdh_ble_observers3$$Limit,                                    
	}
}
static nrf_section_set_t const sdh_ble_observers =                                                   
{                                                                                                   
    .p_first   = sdh_ble_observers_array,                                                           
    .p_last    = sdh_ble_observers_array + ARRAY_SIZE(sdh_ble_observers_array),                     
    .item_size = sizeof(nrf_sdh_ble_evt_observer_t),                                                 
}

2. NRF_SDH_BLE_OBSERVER

#define APP_BLE_OBSERVER_PRIO 1
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
  1. 第一次展开
    简单替换

NRF_SECTION_SET_ITEM_REGISTER(sdh_ble_observers, 1, static nrf_sdh_ble_evt_observer_t _name) =  
{                                                                                                   
	.handler   = _handler,                                                                          
	.p_context = _context                                                                           
}

  1. 第二次展开
    展开NRF_SECTION_SET_ITEM_REGISTER
NRF_SECTION_ITEM_REGISTER(sdh_ble_observers1, m_ble_observer) = {
	.handler   = ble_evt_handler,                                                                          
	.p_context = _context     
}
  1. 第三次展开
    展开NRF_SECTION_ITEM_REGISTER
//表示将变量m_ble_observer 和 段名为sdh_ble_observers1进行绑定,并赋值成大括号里面的内容。
m_ble_observer __attribute__ ((section(STRINGIFY(sdh_ble_observers1)))) __attribute__((used)) = 
{
	.handler   = ble_evt_handler,                                                                          
	.p_context = NULL  
}

四 自定义一个段

根据上述所讲,我们可以在flash中自定义一个段,并给这个段绑定一个变量,下面做个简单例子。

//根据NRF_SDH_BLE_OBSERVER这个宏的真面目,直接写成最终的样子。
typedef struct
{
    nrf_abcdt_handler_t handler;      //!< BLE event handler.
    void *                    p_context;    //!< A parameter to the event handler.
} const nrf_abcd_t;
void last_ching(void * p_context)
{
	NRF_LOG_DEBUG("abcd");
}
NRF_SECTION_ITEM_REGISTER(section_test, static nrf_abcd_t test) = {
	.handler = last_ching,
	.p_context = NULL,
};

//根据NRF_SECTION_SET_DEF这个宏的真面目,直接写成最终的样子。
extern nrf_abcd_t* section_test$$Base;          
extern void      * section_test$$Limit;
static nrf_section_t const sdh_ble_observers_array[] = {
	{                                                                                                   
    	.p_start = &section_test$$Base,                                  
    	.p_end   = &section_test$$Limit,                                    
	}
};

int mian(void)
{
	.....

	nrf_abcd_t    * p_observer;
    nrf_abcdt_handler_t   handler;
    p_observer = (nrf_abcd_t *) sdh_ble_observers_array[0].p_start;
    handler    = p_observer->handler;
    handler(NULL);

	.....
}

在这里插入图片描述
编译之后在.map文件中就可以看到section_test$$ Base的地址为0x354c0,section$ $ Limit的地址为0x354c8,分别对应sdh_ble_observers_array[0].p_start和sdh_ble_observers_array[0].p_end。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值