NRF51822 SDK12.3 事件處理機制

SDK 事件處理機制

書寫規則:
-- 表示調用關係
<- 表示賦值關係
--> 表示執行步驟爲順序執行

簡寫:
SD : SoftDevice

藍牙事件處理:
init:
ble_stack_init -- softdevice_ble_evt_handler_set -- ble_evt_dispatch (m_ble_evt_handler <- ble_evt_dispatch)

execute:
SWI2_IRQHandler(1) -- SD_EVT_IRQHandler -- SOFTDEVICE_EVT_IRQHandler -- intern_softdevice_events_execute -- m_ble_evt_handler


系統事件處理:
init:
ble_stack_init -- softdevice_sys_evt_handler_set -- sys_evt_handler (m_sys_evt_handler <- sys_evt_handler)

execute:
SWI2_IRQHandler(1) -- SD_EVT_IRQHandler -- SOFTDEVICE_EVT_IRQHandler -- intern_softdevice_events_execute -- m_sys_evt_handler


上面能夠看到這兩個主要事件處理都是被 intern_softdevice_events_execute 觸發的,觀察程序(2)能夠看到一樣被這個函數觸發的還有 m_ant_evt_handler(3),它並不是低功耗藍牙,目前並未涉及過.


m_ble_evt_handler 的主要工做是將事件派發給實際組件。而 m_sys_evt_handler 也大同小異。
m_ble_evt_handler 的經常使用組件:
ble_conn_state_on_ble_evt
pm_on_ble_evt
ble_db_discovery_on_ble_evt
ble_conn_params_on_ble_evt
ble_advertising_on_ble_evt
on_ble_evt (自定義的處理)

m_sys_evt_handler 則負責系統內部工做事件處理 ,經常使用的組件有:
fs_sys_event_handler (flash)
ble_advertising_on_sys_evt (處理內容也和flash有關)


(1) SWI: Software Interrupts,即軟件中斷,是NRF51芯片爲軟件中斷預留的一箇中斷。

(2) 取自 SDK12.3\components\softdevice\common\softdevice_handler\softdevice_handler.c
void intern_softdevice_events_execute(void)
{
    if (!m_softdevice_enabled)
    {
        // SoftDevice not enabled. This can be possible if the SoftDevice was enabled by the
        // application without using this module's API (i.e softdevice_handler_init)

        return;
    }
#if NRF_MODULE_ENABLED(CLOCK)
    bool no_more_soc_evts = false;
#else
    bool no_more_soc_evts = (m_sys_evt_handler == NULL);
#endif
#ifdef BLE_STACK_SUPPORT_REQD
    bool no_more_ble_evts = (m_ble_evt_handler == NULL);
#endif
#ifdef ANT_STACK_SUPPORT_REQD
    bool no_more_ant_evts = (m_ant_evt_handler == NULL);
#endif

    for (;;)
    {
        uint32_t err_code;

        if (!no_more_soc_evts)
        {
            if (m_suspended)
            {
                // Cancel pulling next event if event handler was suspended by user.
                return;
            }

            uint32_t evt_id;

            // Pull event from SOC.
            err_code = sd_evt_get(&evt_id);

            if (err_code == NRF_ERROR_NOT_FOUND)
            {
                no_more_soc_evts = true;
            }
            else if (err_code != NRF_SUCCESS)
            {
                APP_ERROR_HANDLER(err_code);
            }
            else
            {
                // Call application's SOC event handler.
#if (NRF_MODULE_ENABLED(CLOCK) && defined(SOFTDEVICE_PRESENT))
                nrf_drv_clock_on_soc_event(evt_id);
                if (m_sys_evt_handler)
                {
                    m_sys_evt_handler(evt_id);
                }
#else
                m_sys_evt_handler(evt_id);
#endif
            }
        }

#ifdef BLE_STACK_SUPPORT_REQD
        // Fetch BLE Events.
        if (!no_more_ble_evts)
        {
            if (m_suspended)
            {
                // Cancel pulling next event if event handler was suspended by user.
                return;
            }

            // Pull event from stack
            uint16_t evt_len = m_ble_evt_buffer_size;

            err_code = sd_ble_evt_get(mp_ble_evt_buffer, &evt_len);
            if (err_code == NRF_ERROR_NOT_FOUND)
            {
                no_more_ble_evts = true;
            }
            else if (err_code != NRF_SUCCESS)
            {
                APP_ERROR_HANDLER(err_code);
            }
            else
            {
                // Call application's BLE stack event handler.
                m_ble_evt_handler((ble_evt_t *)mp_ble_evt_buffer);
            }
        }
#endif

#ifdef ANT_STACK_SUPPORT_REQD
        // Fetch ANT Events.
        if (!no_more_ant_evts)
        {
            if (m_suspended)
            {
                // Cancel pulling next event if event handler was suspended by user.
                return;
            }

            // Pull event from stack
            err_code = sd_ant_event_get(&m_ant_evt_buffer.channel,
                                        &m_ant_evt_buffer.event,
                                        m_ant_evt_buffer.msg.evt_buffer);
            if (err_code == NRF_ERROR_NOT_FOUND)
            {
                no_more_ant_evts = true;
            }
            else if (err_code != NRF_SUCCESS)
            {
                APP_ERROR_HANDLER(err_code);
            }
            else
            {
                // Call application's ANT stack event handler.
                m_ant_evt_handler(&m_ant_evt_buffer);
            }
        }
#endif

        if (no_more_soc_evts)
        {
            // There are no remaining System (SOC) events to be fetched from the SoftDevice.
#if defined(ANT_STACK_SUPPORT_REQD) && defined(BLE_STACK_SUPPORT_REQD)
            // Check if there are any remaining BLE and ANT events.
            if (no_more_ble_evts && no_more_ant_evts)
            {
                break;
            }
#elif defined(BLE_STACK_SUPPORT_REQD)
            // Check if there are any remaining BLE events.
            if (no_more_ble_evts)
            {
                break;
            }
#elif defined(ANT_STACK_SUPPORT_REQD)
            // Check if there are any remaining ANT events.
            if (no_more_ant_evts)
            {
                break;
            }
#else
            // No need to check for BLE or ANT events since there is no support for BLE and ANT
            // required.
            break;
#endif
        }
    }
}

(3) m_ant_evt_handler 是ANT事件處理。ANT不一樣於藍牙,是另外一種無線傳輸協議,它主要運用在運動領域,而低功耗藍牙則是最近才進入運動領域的,因此如今運動領域中最普及的無線傳輸協議仍是ANT。



軟件定時器事件:
init:
APP_TIMER_INIT/APP_TIMER_APPSH_INIT(4) --> app_timer_create --> app_timer_start

execute:
SWI0_IRQHandler -- SWI_IRQHandler -- timer_list_handler

(1) 使用 scheduler 。


能夠看出實際上整個系統的事件處理機制,其底層是 SWI。SWI 是中斷向量表中的一箇中斷(2)。 nrf51 的 SWI 有六個,即 SWI0-SWI5(1)。SDK12.3的協議棧只使用了前三個,分別是SWI0(軟件定時器)、SWI1(無線電)和SWI2(系統事件)(4)。若是要了解 SWI 在中斷中的位置,那麼須要知道它的優先級。SWI0的優先級設置但是在SDK的程序發現,它的優先級爲最低優先級(3)。其他優先級的設置則找不到。可是在NORDIC的官方文檔(5)中關於SWI的描述最後部分能夠推測SWI2 的優先級爲軟件可設的最高優先級(第二高優先級);SWI1爲最高優先級(6)。至於向量表中的其餘經常使用硬件中斷,好比定時器中斷,串口中斷等等,它們的優先級能夠在初始化該外設時自由設置,也可使用SDK中的默認配置,通常狀況下該配置爲3(也就是contex_m0的第四高優先級,其實就是最低優先級APP_IRQ_PRIORITY_LOWEST/_PRIO_APP_LOWEST)(9)。

(1) 《nrf51 reference manual v3.0.1》第三十三章,第二小節。

(2) 取自 SDK12.3\examples\ble_peripheral\ble_app_ancs_c\pca10028\s130\arm5_no_packs\RTE\Device\nRF51422_xxAC\arm_startup_nrf51.s
__Vectors       DCD     __initial_sp              ; Top of Stack
                DCD     Reset_Handler
                DCD     NMI_Handler
                DCD     HardFault_Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     SVC_Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     PendSV_Handler
                DCD     SysTick_Handler

                ; External Interrupts
                DCD     POWER_CLOCK_IRQHandler
                DCD     RADIO_IRQHandler
                DCD     UART0_IRQHandler
                DCD     SPI0_TWI0_IRQHandler
                DCD     SPI1_TWI1_IRQHandler
                DCD     0                         ; Reserved
                DCD     GPIOTE_IRQHandler
                DCD     ADC_IRQHandler
                DCD     TIMER0_IRQHandler
                DCD     TIMER1_IRQHandler
                DCD     TIMER2_IRQHandler
                DCD     RTC0_IRQHandler
                DCD     TEMP_IRQHandler
                DCD     RNG_IRQHandler
                DCD     ECB_IRQHandler
                DCD     CCM_AAR_IRQHandler
                DCD     WDT_IRQHandler
                DCD     RTC1_IRQHandler
                DCD     QDEC_IRQHandler
                DCD     LPCOMP_IRQHandler
                DCD     SWI0_IRQHandler
                DCD     SWI1_IRQHandler
                DCD     SWI2_IRQHandler
                DCD     SWI3_IRQHandler
                DCD     SWI4_IRQHandler
                DCD     SWI5_IRQHandler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved

__Vectors_End

(3) SDK12.3\components\libraries\timer\app_timer.c 第五十行和第九百二十七行
#define SWI_IRQ_PRI             APP_IRQ_PRIORITY_LOWEST                        /**< Priority of the SWI  interrupt (used for updating the timer list). */


uint32_t app_timer_init(uint32_t                      prescaler,
                        uint8_t                       op_queue_size,
                        void *                        p_buffer,
                        app_timer_evt_schedule_func_t evt_schedule_func)
{
    // Check that buffer is correctly aligned
    if (!is_word_aligned(p_buffer))
    {
        return NRF_ERROR_INVALID_PARAM;
    }
    // Check for NULL buffer
    if (p_buffer == NULL)
    {
        return NRF_ERROR_INVALID_PARAM;
    }

    // Stop RTC to prevent any running timers from expiring (in case of reinitialization)
    rtc1_stop();

    m_evt_schedule_func = evt_schedule_func;

    // Initialize operation queue
    m_op_queue.first           = 0;
    m_op_queue.last            = 0;
    m_op_queue.size            = op_queue_size;
    m_op_queue.p_user_op_queue = p_buffer;

    mp_timer_id_head            = NULL;
    m_ticks_elapsed_q_read_ind  = 0;
    m_ticks_elapsed_q_write_ind = 0;

#if APP_TIMER_WITH_PROFILER
    m_max_user_op_queue_utilization   = 0;
#endif

    NVIC_ClearPendingIRQ(SWI_IRQn);
    NVIC_SetPriority(SWI_IRQn, SWI_IRQ_PRI);
    NVIC_EnableIRQ(SWI_IRQn);

    rtc1_init(prescaler);

    m_ticks_latest = rtc1_counter_get();

    return NRF_SUCCESS;
}

(4) SDK12.3\components\libraries\timer\app_timer.c 第六十五行
SDK12.3\components\softdevice\s130\headers\nrf_soc.h 第七十九行和第七十七行
#define SWI_IRQHandler SWI0_IRQHandler
#define RADIO_NOTIFICATION_IRQHandler     (SWI1_IRQHandler)  /**< The radio notification IRQ handler. */
#define SD_EVT_IRQHandler                 (SWI2_IRQHandler)  /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. */

(5) 指的是 NORDIC/Support&Communlty/DOCUMENTATION

(6) NORDIC/Support&Communlty/DOCUMENTATION/Software Development Kit > nRF5 SDK > nRF5 SDK v12.3.0 > Hardware Drivers > SWI 最後一部分 Usage with a SoftDevice
Be careful when specifiying APP_IRQ_PRIORITY_HIGH as SWI priority. Long interrupt routines with high priority might affect the proper operation of the SoftDevice.
這裏說若是有一個很長的 APP_IRQ_PRIORITY_HIGH 優先級的應用程序,會影響軟件協議棧進行適當操做。
而軟件協議棧的職能是實現無線電協議(7),在SDK源碼中能夠看到若是使用協議棧,那麼APP最高優先級爲cortex_m0的第二高優先級(8)。既然說APP可能會影響軟件協議棧進行適當操做,那麼推測軟件協議棧處理程序的優先級爲 APP_IRQ_PRIORITY_HIGH 是合理的。另外,cortex_m0的第一高優先級只能提供給軟件協議棧,它據此實現無線電協議。

(7) NORDIC/Support&Communlty/DOCUMENTATION/cortex_m0 > SoftDevice
A SoftDevice is a precompiled and linked binary software implementing a wireless protocol developed by Nordic Semiconductor.
軟件協議棧是預編譯的,即不可見的,用來實現無線協議。

(8) SDK12.3\components\libraries\util\app_util_platform.h 第六十七行和第九十一行
#if __CORTEX_M == (0x00U)
#define _PRIO_SD_HIGH       0
#define _PRIO_APP_HIGH      1
#define _PRIO_APP_MID       1
#define _PRIO_SD_LOW        2
#define _PRIO_APP_LOW       3
#define _PRIO_APP_LOWEST    3
#define _PRIO_THREAD        4
#elif __CORTEX_M == (0x04U)
#define _PRIO_SD_HIGH       0
#define _PRIO_SD_MID        1
#define _PRIO_APP_HIGH      2
#define _PRIO_APP_MID       3
#define _PRIO_SD_LOW        4
#define _PRIO_SD_LOWEST     5
#define _PRIO_APP_LOW       6
#define _PRIO_APP_LOWEST    7
#define _PRIO_THREAD        15
#else
    #error "No platform defined"
#endif

//lint -save -e113 -e452
/**@brief The interrupt priorities available to the application while the SoftDevice is active. */
typedef enum
{
#ifndef SOFTDEVICE_PRESENT
    APP_IRQ_PRIORITY_HIGHEST = _PRIO_SD_HIGH,
#else
    APP_IRQ_PRIORITY_HIGHEST = _PRIO_APP_HIGH,
#endif
    APP_IRQ_PRIORITY_HIGH    = _PRIO_APP_HIGH,
#ifndef SOFTDEVICE_PRESENT
    APP_IRQ_PRIORITY_MID     = _PRIO_SD_LOW,
#else
    APP_IRQ_PRIORITY_MID     = _PRIO_APP_MID,
#endif
    APP_IRQ_PRIORITY_LOW     = _PRIO_APP_LOW,
    APP_IRQ_PRIORITY_LOWEST  = _PRIO_APP_LOWEST,
    APP_IRQ_PRIORITY_THREAD  = _PRIO_THREAD     /**< "Interrupt level" when running in Thread Mode. */
} app_irq_priority_t;
//lint -restore

(9) SDK12.3
__Vectors       DCD     __initial_sp              ; Top of Stack
                DCD     Reset_Handler
                DCD     NMI_Handler
                DCD     HardFault_Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     SVC_Handler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     PendSV_Handler
                DCD     SysTick_Handler

                ; External Interrupts
                DCD     POWER_CLOCK_IRQHandler
                DCD     RADIO_IRQHandler
                DCD     UART0_IRQHandler        ; #define UART_DEFAULT_CONFIG_IRQ_PRIORITY 3
                DCD     SPI0_TWI0_IRQHandler
                DCD     SPI1_TWI1_IRQHandler
                DCD     0                         ; Reserved
                DCD     GPIOTE_IRQHandler        ; #define GPIOTE_CONFIG_IRQ_PRIORITY 3
                DCD     ADC_IRQHandler            ; #define ADC_CONFIG_IRQ_PRIORITY 3
                DCD     TIMER0_IRQHandler        ; #define TIMER_DEFAULT_CONFIG_IRQ_PRIORITY 3
                DCD     TIMER1_IRQHandler            
                DCD     TIMER2_IRQHandler
                DCD     RTC0_IRQHandler
                DCD     TEMP_IRQHandler
                DCD     RNG_IRQHandler
                DCD     ECB_IRQHandler
                DCD     CCM_AAR_IRQHandler
                DCD     WDT_IRQHandler            ; #define WDT_CONFIG_IRQ_PRIORITY 3
                DCD     RTC1_IRQHandler
                DCD     QDEC_IRQHandler
                DCD     LPCOMP_IRQHandler
                DCD     SWI0_IRQHandler
                DCD     SWI1_IRQHandler
                DCD     SWI2_IRQHandler
                DCD     SWI3_IRQHandler
                DCD     SWI4_IRQHandler
                DCD     SWI5_IRQHandler
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved
                DCD     0                         ; Reserved

__Vectors_End


上面的資料說明,按照標準配置,咱們足以構建出一個優先保證藍牙工做的系統。在這個系統中,也提供有一個設置能夠致使該穩定性崩盤,那就是scheduler,它的做用是在中斷產生後將它轉移至線程模式,即在main循環中執行。不過,scheduler能夠將藍牙協議棧事件處理和/或定時器事件處理轉移至線程模式,若是scheduler僅轉移定時器處理,那麼從理論上是沒有危險的。若是我上述認識都沒有錯,那這麼看來,這整個事件處理系統是首先保證藍牙無線功能的正常使用的,然而在實際使用中居然出現藍牙屢屢崩潰的狀況,這實在使人費解。


app

相關文章
相關標籤/搜索