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

BLE interrupt priority question and BLE event lost issue

Hi,

I use nrf51822 + S130 platform, in my application I used ADC,UART and APP TIMER, I mens only these can cause interruptions,all these interrupt priority is 3(APP_IRQ_PRIORITY_LOWEST), The related code is as follows:

ADC init function in main.c:

/**
 * @brief ADC initialization.
 */
static void adc_init(void)
{
    ret_code_t ret_code;
    nrf_drv_adc_config_t config = NRF_DRV_ADC_DEFAULT_CONFIG;

    ret_code = nrf_drv_adc_init(&config, adc_event_handler);
    APP_ERROR_CHECK(ret_code);

    m_accelerator_channel_config.config.config.input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD;
    m_break_channel_config.config.config.input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD;
    m_accelerator_channel_child_config.config.config.input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD;
    m_break_channel_child_config.config.config.input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD;
    m_power_channel_config.config.config.input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD;
    
    nrf_drv_adc_channel_enable(&m_accelerator_channel_config);
    nrf_drv_adc_channel_enable(&m_break_channel_config);
    nrf_drv_adc_channel_enable(&m_accelerator_channel_child_config);
    nrf_drv_adc_channel_enable(&m_break_channel_child_config);
    nrf_drv_adc_channel_enable(&m_power_channel_config);
    
    adc_start();
}

ADC event hadler in main.c:

/**
 * @brief ADC interrupt handler.
 */
static void adc_event_handler(nrf_drv_adc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_ADC_EVT_DONE)
    {
        adc_start();
    }
}

ADC interrupt priority define in sdk_config.h:

#ifndef ADC_ENABLED
#define ADC_ENABLED 1
#endif
#if  ADC_ENABLED
// <o> ADC_CONFIG_IRQ_PRIORITY  - Interrupt priority
 

// <i> Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
// <0=> 0 (highest) 
// <1=> 1 
// <2=> 2 
// <3=> 3 

#ifndef ADC_CONFIG_IRQ_PRIORITY
#define ADC_CONFIG_IRQ_PRIORITY 3
#endif

UART init function in main.c:

/**@brief Function for initializing the UART.
 */
static void uart_init(void)
{
    uint32_t err_code;

    app_fifo_init(&s_tUARTRxFIFO, s_ucUARTRxFIFOBuf, 128);
    
    const app_uart_comm_params_t comm_params =
      {
        .rx_pin_no    = RX_PIN_NUMBER,
        .tx_pin_no    = TX_PIN_NUMBER,
        .rts_pin_no   = RTS_PIN_NUMBER,
        .cts_pin_no   = CTS_PIN_NUMBER,
        .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
        .use_parity   = false,
        .baud_rate    = UART_BAUDRATE_BAUDRATE_Baud115200
      };

    APP_UART_FIFO_INIT(&comm_params,
                        UART_RX_BUF_SIZE,
                        UART_TX_BUF_SIZE,
                        uart_event_handle,
                        APP_IRQ_PRIORITY_LOWEST,
                        err_code);
      
    APP_ERROR_CHECK(err_code);
}

UART event handler in main.c:

void uart_event_handle(app_uart_evt_t * p_event)
{
    uint8_t data;

    switch (p_event->evt_type)
    {
        /**@snippet [Handling data from UART] */
        case APP_UART_DATA_READY:      
            app_uart_get(&data);
            
            app_fifo_put(&s_tUARTRxFIFO, data);
    
            break;
        default:
            break;
    }
}

APP Timer init in main.c:

APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, NULL);

    app_timer_create(&system_timer_id, APP_TIMER_MODE_REPEATED, system_timer_handler);
    app_timer_start(system_timer_id, 32, NULL);

APP Timer event handler in main.c:

/** @brief system_timer_handler.
 */
void system_timer_handler(void * p_context)
{
    static uint8_t div_cnt = 0;
    uint32_t i;
    
    //parse data from COM and BLE every 5ms
    if (div_cnt++ == 5)
    {
        div_cnt = 0;
        
        MiniResponeDataParse();
        BLEPeripheralDataParse();
    }
    
    //process beep keep
    if (g_ulBeepKeepTime)
    {
        g_ulBeepKeepTime--;
        
        if (!g_ulBeepKeepTime)
        {
            nrf_gpio_pin_write(BEEP_PIN, BEEP_ACTIVE_STATE ? 0 : 1);
        }
    }
    
    //process counters
    for (i = 0; i < 16; i++)
    {
        if (g_tMainLoopInterface.pCounter[i])
        {
            if (*g_tMainLoopInterface.pCounter[i])
            {
                (*g_tMainLoopInterface.pCounter[i])--;
            }
        }
    }
}

APP Timer related interrupt priority define in app_timer.c:

#define RTC1_IRQ_PRI            APP_IRQ_PRIORITY_LOWEST                        /**< Priority of the RTC1 interrupt (used for checking for timeouts and executing timeout handlers). */
#define SWI_IRQ_PRI             APP_IRQ_PRIORITY_LOWEST                        /**< Priority of the SWI  interrupt (used for updating the timer list). */

APP_IRQ_PRIORITY_LOWEST define in 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

So all my user interrupt priority is the lowest(3). I reference from here link text and here link text to know that the BLE Event interrupt priority is 2, is that right? So the ble_evt_dispatch function will not be affected by other user interrupts(ADC UART APP TIMER) because its interrupt priority is higher than they are,right?

Then, if what i said above is right, here's my problem.I use a variable named m_conn_tx_packet_count to record tx packet count, when connect be established I call sd_ble_tx_packet_count_get to get the total number of available guaranteed application transmission packets, when ble_nus_c_string_send return NRF_SUCCESS i decreasing m_conn_tx_packet_count,when receive BLE_EVT_TX_COMPLETE event i increasing m_conn_tx_packet_count,so i can call ble_nus_c_string_send only when there are free tx packets. The code is:

static void on_ble_central_evt(const ble_evt_t * const p_ble_evt)
{
    const ble_gap_evt_t   * const p_gap_evt = &p_ble_evt->evt.gap_evt;
    ret_code_t                    err_code;

    switch (p_ble_evt->header.evt_id)
    {
        /** Upon connection, check which peripheral has connected (HR or RSC), initiate DB
         *  discovery, update LEDs status and resume scanning if necessary. */
        case BLE_GAP_EVT_CONNECTED:
        {
            int i = 0, j = 0;
            
            NRF_LOG_INFO("Central Connected \r\n");
            /** If no nus is currently connected, try to find it on this peripheral*/
            
            for (i = 0; i < CENTRAL_LINK_COUNT; i++)
            {
                for (j = 0; j < 6; j++)
                {
                    if (p_gap_evt->params.connected.peer_addr.addr[j] != g_tMainLoopInterface.peripheral_info[i].mac[5 - j])
                    {
                        break;
                    }
                }
                
                if (j != 6)
                {
                    continue;
                }
                
                m_conn_handle_nus_c[i] = p_gap_evt->conn_handle;
                
                sd_ble_tx_packet_count_get(p_gap_evt->conn_handle, (uint8_t *)&m_conn_tx_packet_count[i]);
              
                break;
            }

        } break; // BLE_GAP_EVT_CONNECTED

        case BLE_EVT_TX_COMPLETE:
            for (uint8_t i = 0; i < CENTRAL_LINK_COUNT; i++)
            {
                if (p_gap_evt->conn_handle == m_conn_handle_nus_c[i])
                {
                    m_conn_tx_packet_count[i]++;
                    break;
                }
            }
            break;
        default:
            // No implementation needed.
            break;
    }
} 

My data send function code:

bool SendDatas(...)
{
    ....//other code

    if (m_conn_tx_packet_count[pars->peripheral_id] != 0)
    {
         if (ble_nus_c_string_send(p_ble_nus_c, &txbuf[send_index], factlen) == NRF_SUCCESS)
         {
              m_conn_tx_packet_count[pars->peripheral_id]--;
                        
              return true;
          }
   }

    return false;
}

Now the problem is, some times ble_nus_c_string_send never be called, because m_conn_tx_packet_count[pars->peripheral_id] always be 0. It seems like the last ble_nus_c_string_send call return NRF_SUCCESS but there's no BLE_EVT_TX_COMPLETE event received. Is it possible that the soft device lost BLE event? I've had similar problems before, and I have not solved them well,the link is herelink text . Both the two problem indicate that maybe some SYSTEM EVENT(BLE EVENT) have been lost. So I check all my interrupt config to make sure no interrupt's priority is higher than the priority of SOFTDEVICE_EVT_IRQ.

So, what wrong with my code? Was I not using the S130 correctly? Or is it the issue of S130?

Parents
  • I debug the program again, I watch NVIC_IP register and call NVIC_GetPriority(SD_EVT_IRQn) function,they all showed that the priority of SD_EVT_IRQn is 3! In this case,maybe my other interrupt which the priority is also 3 cause the SD EVENT lost i guess. But 3 is the lowest priority i can use, I have no choice without it, unless I do not use interrupt.

    I tried change the priority of SD_EVT_IRQn use NVIC_SetPriority(SD_EVT_IRQn, 2), but no matter where i use it (e.g. before or after SOFTDEVICE_HANDLER_INIT,before or after softdevice_enable_get_default_config, before or after softdevice_enable) the program will crash.

    In conclusion, there are two questions I want to confirm:

    1、Will my interrupt with the same priority of SD_EVT_IRQn cause BLE EVENT lost?

    2、How can I set or change the priority of SD_EVT_IRQn?

Reply
  • I debug the program again, I watch NVIC_IP register and call NVIC_GetPriority(SD_EVT_IRQn) function,they all showed that the priority of SD_EVT_IRQn is 3! In this case,maybe my other interrupt which the priority is also 3 cause the SD EVENT lost i guess. But 3 is the lowest priority i can use, I have no choice without it, unless I do not use interrupt.

    I tried change the priority of SD_EVT_IRQn use NVIC_SetPriority(SD_EVT_IRQn, 2), but no matter where i use it (e.g. before or after SOFTDEVICE_HANDLER_INIT,before or after softdevice_enable_get_default_config, before or after softdevice_enable) the program will crash.

    In conclusion, there are two questions I want to confirm:

    1、Will my interrupt with the same priority of SD_EVT_IRQn cause BLE EVENT lost?

    2、How can I set or change the priority of SD_EVT_IRQn?

Children
No Data
Related