一 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表示段结束地址
- 第一次展开
替换变量
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), \
}
- 第二次展开
展开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), \
}
- 第三次展开
展开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),
}
- 第四次展开
展开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);
- 第一次展开
简单替换
NRF_SECTION_SET_ITEM_REGISTER(sdh_ble_observers, 1, static nrf_sdh_ble_evt_observer_t _name) =
{
.handler = _handler,
.p_context = _context
}
- 第二次展开
展开NRF_SECTION_SET_ITEM_REGISTER
NRF_SECTION_ITEM_REGISTER(sdh_ble_observers1, m_ble_observer) = {
.handler = ble_evt_handler,
.p_context = _context
}
- 第三次展开
展开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 = §ion_test$$Base,
.p_end = §ion_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。