0

Timer interrupt don't work in ble_app_uart of SDK6.1.0

sarsgg444 gravatar image

asked 2017-04-06 08:19:54 +0200

updated 2017-04-07 10:36:51 +0200

Hello everybody

I am working with the Raytac BLE Module "MDBT40", which is based on nrf51822.

And I am testing example project "ble_app_uart" in the SDK6.1.0 now.

But there are some problems when I add a new timer.

In the project "ble_app_uart", It contain only RTC timer.

However, I can't understand how the RTC interrupt work in the demo code.

So I add a timer2 in the project as below.

I hope it turn on LED once 100ms.

void start_timer2(void)
{       
  // Start 16 MHz crystal oscillator.
  NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;   
  NRF_CLOCK->TASKS_HFCLKSTART    = 1;   

  while(NRF_CLOCK->EVENTS_HFCLKSTARTED==0){}

  NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;  // Set the timer in Counter Mode
  NRF_TIMER2->TASKS_CLEAR = 1;               // clear the task first to be usable for later
  NRF_TIMER2->PRESCALER = 9;                             //Set prescaler. Higher number gives slower timer. Prescaler = 0 gives 16MHz timer. Prescaler = 9 gives 31250 Hz timer, 1tick 32us.
  NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;         //Set counter to 16 bit resolution
  NRF_TIMER2->CC[0] = 3125;                              //Set value for TIMER2 compare register 0. Period is 32us * 3125 = 100ms.

  // Enable interrupt on Timer 2, for CC[0] 
  NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);
  NVIC_EnableIRQ(TIMER2_IRQn);

  NRF_TIMER2->TASKS_START = 1;               // Start TIMER2
}

/** TIMTER1 peripheral interrupt handler. This interrupt handler is called whenever there it a TIMER1 interrupt
 */
void TIMER2_IRQHandler(void)
{
    if ((NRF_TIMER2->EVENTS_COMPARE[0] != 0) && ((NRF_TIMER2->INTENSET & TIMER_INTENSET_COMPARE0_Msk) != 0))
  {
        NRF_TIMER2->EVENTS_COMPARE[0] = 0;           //Clear compare register 0 event   
        NRF_TIMER2->TASKS_CLEAR=1;

        // turn on LED
        nrf_gpio_pin_set(D03);
        while(1){};
  }
}

And I put "start_timer2();" after "timers_init();" in main function.

But it doesn't interrupt while running.

What I miss in the process?

Sorry for my poor English.

And thanks in advance!


More test information

this is my main function

int main(void)
{

    static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    static uint8_t index = 0;
    uint8_t index_backup = 0;
    uint8_t newbyte;
        int i=0;

    // Initialize
    gpio_init();
    timers_init();
    start_timer2(); 
    uart_init();
    ble_stack_init();
    gap_params_init();
    services_init();
    advertising_init();
    conn_params_init();
    sec_params_init();

    uart_putstring((const uint8_t *)START_STRING);

    advertising_start();

    // Enter main loop
    for (;;)
    { 
        /*Stop reading new data if there are no ble buffers available */
        if(ble_buffer_available)
        {
            if(app_uart_get(&newbyte) == NRF_SUCCESS)
            {
                data_array[index] = newbyte;

                if (data_array[index] == '\n')
                        {
                    ble_buffer_available = ble_attempt_to_send(&data_array[0],index);
                    index_backup = index;
                      if(ble_buffer_available) index = 0; 
                        }
                else if (index == (BLE_NUS_MAX_DATA_LEN-1))
                        {                            
                    ble_buffer_available = ble_attempt_to_send(&data_array[0],index+1);
                    index_backup = index+1;
                    if(ble_buffer_available) index = 0;                 
                        }
                        else
                        {
                            index++;
                        }
            }
        }


        /* Re-transmission if ble_buffer_available was set to false*/
        if(tx_complete)
        {
            tx_complete=false;
            index = index_backup;
            ble_buffer_available = ble_attempt_to_send(&data_array[0],index);
            if(ble_buffer_available) index = 0;
        }

        power_manage();
    }
}

For testing, I turn on LED to make sure when process get trouble.

And process stop between turnonLED1 and turnonLED2 which in ble_stack_init();

    static void ble_stack_init(void)
{
    uint32_t err_code;

    nrf_gpio_cfg_input(EXT_XTAL_MODE,NRF_GPIO_PIN_PULLUP);

    TurnonLED1();

      if(nrf_gpio_pin_read(EXT_XTAL_MODE) == 1) 
      {
          // Initialize SoftDevice.
        SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_RC_250_PPM_1000MS_CALIBRATION, false);
      }
      else
      {
          // Initialize SoftDevice.
        SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);
      }

    TurnonLED2();   

    // Enable BLE stack 
    ble_enable_params_t ble_enable_params;
    memset(&ble_enable_params, 0, sizeof(ble_enable_params));
    ble_enable_params.gatts_enable_params.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT;
    err_code = sd_ble_enable(&ble_enable_params);
    APP_ERROR_CHECK(err_code);

    // Subscribe for BLE events.
    err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
    APP_ERROR_CHECK(err_code);
}

Then I change position of start_time2(); in main(); as below

    int main(void)
{

    static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    static uint8_t index = 0;
    uint8_t index_backup = 0;
    uint8_t newbyte;
        int i=0;

    // Initialize
    //leds_init();
        gpio_init();
    timers_init();

        nrf_gpio_pin_clear(DIG3); 
    //buttons_init();
    uart_init();
    ble_stack_init();
    gap_params_init();
    services_init();
    advertising_init();
    conn_params_init();
    sec_params_init();

    uart_putstring((const uint8_t *)START_STRING);

        start_timer2();

    advertising_start();
    //skip...
}

Process stop between turnonLED3 and turnonLED4 which in start_timer2();

    void start_timer2(void)
{       
    turnonLED3();

    // Start 16 MHz crystal oscillator.
    NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; 
    NRF_CLOCK->TASKS_HFCLKSTART    = 1; 

    turnonLED4();

    while(NRF_CLOCK->EVENTS_HFCLKSTARTED==0){}

    NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;  // Set the timer in Counter Mode
    NRF_TIMER2->TASKS_CLEAR = 1;               // clear the task first to be usable for later
    NRF_TIMER2->PRESCALER = 9;                             //Set prescaler. Higher number gives slower timer. Prescaler = 0 gives 16MHz timer. Prescaler = 9 gives 31250 Hz timer, 1tick 32us.
    NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;       //Set counter to 16 bit resolution
    NRF_TIMER2->CC[0] = 3125;                              //Set value for TIMER2 compare register 0. Period is 32us * 3125 = 100ms.

  // Enable interrupt on Timer 2, both for CC[0] and CC[1] compare match events
    NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos);
  NVIC_EnableIRQ(TIMER2_IRQn);

  NRF_TIMER2->TASKS_START = 1;               // Start TIMER2

}

Maybe it helpful to find problem?


Just more testing

I use app_timer instead of timer2.

It's working but "TIMER_INTERVAL" didn't perform as expected.(It take longer than 1ms to trigger interrupt.)

Are there higher priority interrupt cause it?(Bluetooth or Uart?)

And why timer2 can't work fine?

#define APP_TIMER_PRESCALER             0                                           /**< Value of the RTC1 PRESCALER register. */
#define APP_TIMER_MAX_TIMERS            2                                           /**< Maximum number of simultaneously created timers. */
#define APP_TIMER_OP_QUEUE_SIZE         4                                           /**< Size of timer operation queues. */

static app_timer_id_t  m_app_timer_id;
#define TIMER_INTERVAL  APP_TIMER_TICKS(1, APP_TIMER_PRESCALER) // Timer_interval is 1ms 

static void start_timer(void)
{
    uint32_t err_code;

    err_code = app_timer_start(m_app_timer_id, TIMER_INTERVAL, NULL);
    APP_ERROR_CHECK(err_code);
}

void display_timeout_handler(void * p_context)
{
        DriveXDig7Segment();
}

int main(void)
{

    static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    static uint8_t index = 0;
    uint8_t index_backup = 0;
    uint8_t newbyte;

    // Initialize
    //leds_init();
        gpio_init();
    timers_init();
    //buttons_init();
    uart_init();
    ble_stack_init();
    gap_params_init();
    services_init();
    advertising_init();
    conn_params_init();
    sec_params_init();

    uart_putstring((const uint8_t *)START_STRING);

        start_timer();

    advertising_start();

    skip...
}
edit retag flag offensive close delete report spam

Comments

Have you configured the GPIO to be an output? nrf_gpio_cfg_output()? Are you sure that nrf_gpio_pin_set() will turn the LED on? Maybe you have to call nrf_gpio_pin_clear()? Have you tried to use the debugger? If you put a breakpoint in TIMER2_IRQHandler(), do you hit it?

Petter Myhre ( 2017-04-06 13:49:11 +0200 )editconvert to answer

Hi Petter. I am sure I have configured the GPIO to be an output. And function "TurnonLEDx" actually working. I don't know how to step by step debug with nrf51288 directly. I program with Keil5. I first build a hex file,then upload "S110 SoftDevice v7.0" and "hex file" by "nrfgo studio". I also put TurnonLEDx and delay in TIMER2_IRQHandler(),but it doesn't be trrigged.

pikachu ( 2017-04-06 15:34:55 +0200 )editconvert to answer

Ok. I would recommend you to look into how to use the debugger.

Maybe the problem is that you are accessing the NRF_CLOCK peripheral directly? This is a restricted peripheral when the SoftDevice is enabled, see Section 11.3 in the S110 SoftDevice specification 2.0 for more information. You can instead try to call sd_clock_hfclk_request().

Petter Myhre ( 2017-04-06 15:59:08 +0200 )editconvert to answer

Hi Petter.

I fix code by calling "sd_clock_hfclk_request();" instead of "NRF_CLOCK->TASKS_HFCLKSTART = 1;" But it still work in trouble.

  1. It can work when "start_timer2();" is after "uart_putstring((const uint8_t *)START_STRING);", but not work when "start_timer2();" is after "timers_init();".

  2. Timer2 interrput is triggered with the same time, no matter NRF_TIMER2->CC[0] = 1 ,10, 100. Maybe the higher priority interrupt be triggered, and take long time.(I guess it's BLE or uart)

pikachu ( 2017-04-07 05:20:14 +0200 )editconvert to answer

Ok. So what happens when put it after timers_init()? Are you able to execute the start_timer2() function? Do you get to ble_stack_init();? Please try to use the debug.

Same time? How are you measuring this?

Petter Myhre ( 2017-04-07 13:43:22 +0200 )editconvert to answer

Hi Petter.

I debug with RTT viewer by "SEGGER_RTT_WriteString" and "SEGGER_RTT_printf".

When "start_timer2();" is before "ble_stack_init();", process reset repeatedly and return to beginning of main.

"ble_stack_init();" seem contain something about "softdevice_handler_init", lfclk init, ...

I don't know how it work and take how it affect timer2(Maybe it affect hfclk actually).

pikachu ( 2017-04-12 09:34:15 +0200 )editconvert to answer

Here is code.

static void ble_stack_init(void)
{
    uint32_t err_code;

    nrf_gpio_cfg_input(EXT_XTAL_MODE,NRF_GPIO_PIN_PULLUP);

    // Initialize SoftDevice.
      if(nrf_gpio_pin_read(EXT_XTAL_MODE) == 1) 
      {
        SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_RC_250_PPM_1000MS_CALIBRATION, false);
      }
      else
      {
        SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);
      }

    // Enable BLE stack 
    ble_enable_params_t ble_enable_params;
    memset(&ble_enable_params, 0, sizeof(ble_enable_params));
    ble_enable_params.gatts_enable_params.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT;
    err_code = sd_ble_enable(&ble_enable_params);
    APP_ERROR_CHECK(err_code);

    // Subscribe for BLE events.
    err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
    APP_ERROR_CHECK(err_code);
}
pikachu ( 2017-04-12 09:38:05 +0200 )editconvert to answer

int main(void) {

    static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    static uint8_t index = 0;
    uint8_t index_backup = 0;
    uint8_t newbyte;
    uint32_t isrunning = 0;

    g_CounterDriveSegment = 0;

    #ifdef NRF_RTT_SHOW
    SEGGER_RTT_WriteString(0, "Main Start!\n");
    #endif

    // Initialize
    gpio_init();
    timers_init();
    uart_init();
    ble_stack_init();
start_timer2();
    gap_params_init();
    services_init();
    advertising_init();
    conn_params_init();
    sec_params_init();

    uart_putstring((const uint8_t *)START_STRING);

    advertising_start();

    #ifdef NRF_RTT_SHOW
    SEGGER_RTT_WriteString(0, "Loop Start!\n");
    #endif

    // Enter main loop
    for (;;)
    { SKIP...}
}
pikachu ( 2017-04-12 09:49:44 +0200 )editconvert to answer

Where does it reset? Do you get to ble_stack_init()? Have you seen this?

Petter Myhre ( 2017-04-12 10:01:35 +0200 )editconvert to answer

Hi Petter

I put some printf in "SOFTDEVICE_HANDLER_INIT".

But it didn't finish "softdevice_handler_init".

So I didn't get ERROR_CODE value.

pikachu ( 2017-04-14 05:00:33 +0200 )editconvert to answer

position of printf

#define SOFTDEVICE_HANDLER_INIT(CLOCK_SOURCE,
                                USE_SCHEDULER)
do
{
    static uint32_t EVT_BUFFER[CEIL_DIV(MAX(
        MAX(BLE_STACK_EVT_MSG_BUF_SIZE,
        ANT_STACK_EVT_STRUCT_SIZE),
        SYS_EVT_MSG_BUF_SIZE
        ),
        sizeof(uint32_t))];
    uint32_t ERR_CODE;
    SEGGER_RTT_WriteString(0, "c1 \n");  //-->here
    ERR_CODE = softdevice_handler_init((CLOCK_SOURCE),
        EVT_BUFFER,
        sizeof(EVT_BUFFER),
        (USE_SCHEDULER) ? softdevice_evt_schedule : NULL);
    SEGGER_RTT_WriteString(0, "c2 \n");  //-->here
    APP_ERROR_CHECK(ERR_CODE);
} while (0)
pikachu ( 2017-04-14 05:09:01 +0200 )editconvert to answer

position of printf

uint32_t softdevice_handler_init(nrf_clock_lfclksrc_t clock_source,
                                                 void * p_evt_buffer,
                                                 uint16_t evt_buffer_size,
                                                 softdevice_evt_schedule_func_t evt_schedule_func)
{
    uint32_t err_code;

    SEGGER_RTT_WriteString(0, "c3 \n");

skip...
}
pikachu ( 2017-04-14 05:14:10 +0200 )editconvert to answer

The result

# SEGGER J-Link RTT Viewer V6.14c Terminal Log File
# Compiled: 17:46:54 on Mar 31 2017
# Logging started @ 14 Apr 2017 11:17:06
 0> Main Start!
 0> c1 
 0> Main Start!
 0> c1 
 0> Main Start!
 0> c1 
 0> Main Start!
 0> c1 
 0> Main Start!
 0> c1 
 0> Main Start!
 0> c1 
 0> Main Start!
 0> Main Start!
 0> Main Start!
 0> c1 
 0> MainMain Start!
 0> c1 
 0> Main StaMain Start!
 0> c1 
 0> Main Start!
 0> Main Start!
 0> Main Start!
 0> c1 
 0> Main Start!
 0> c1 
 0> Main Start!
 0> c1 
 0> Main Start!
 0> Main Start!
 0> c1 
skip..
pikachu ( 2017-04-14 05:17:56 +0200 )editconvert to answer

Strange. Could you upload your complete project so I can test it here?

Petter Myhre ( 2017-04-18 17:08:46 +0200 )editconvert to answer

Hi Petter

https://drive.google.com/file/d/0Byhx...

I delete other project which was not used in SDK.

My project path is .\nRF51 SDK_v6.1.0.0\Nordic\nrf51822\Board\nrf6310\s110\nrf51-UART-examples-master\app_uart_library_example_with_ble

If I loss something, please tell me.

Thanks.

pikachu ( 2017-04-19 16:16:33 +0200 )editconvert to answer

Seems to be working fine here. It advertises and I get the following in the RTT viewer:

 0> Main Start!
 0> Loop Start!

Do you have another chip to test with?

Could you test with the attached hex files:

SoftDevice

Application

Petter Myhre ( 2017-04-20 14:39:04 +0200 )editconvert to answer

Hi Petter

I am sorry that I forget to adjust main which run in trouble.

Can you adjust main as follow and try again?

int main(void)
{

    static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];
    static uint8_t index = 0;
    uint8_t index_backup = 0;
    uint8_t newbyte;
        uint32_t isrunning = 0;

        g_CounterDriveSegment = 0;

        #ifdef NRF_RTT_SHOW
        SEGGER_RTT_WriteString(0, "Main Start!\n");
        #endif

    // Initialize
    gpio_init();
    timers_init();
    uart_init();
   // put start_timer2 will run introuble
    start_timer2();
   // put start_timer2 will run introuble
    ble_stack_init();
    gap_params_init();
    services_init();
    advertising_init();
    conn_params_init();
    sec_params_init();

    uart_putstring((const uint8_t *)START_STRING);

    advertising_start();

skip...
}
pikachu ( 2017-04-20 18:22:24 +0200 )editconvert to answer

1 answer

Sort by ยป oldest newest most voted
1
Petter gravatar image

answered 2017-04-21 11:56:10 +0200

Now I was able to reproduce. sd_softdevice_enable() returns 0x1001 -> NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION

This is because you have enabled the TIMER2 peripheral with interrupt priority 0, which is reserved by the SoftDevice. Add the following to remove the error:

NVIC_SetPriority(TIMER2_IRQn, 3);
edit flag offensive delete publish link more

Comments

Hi Petter

It's working!

So I had better enabled the peripheral(which didn't be used in softdevice) with interrupt priority 1 or 3 before using it.

Thank you.

pikachu ( 2017-04-25 04:58:32 +0200 )editconvert to answer

Great! :) If I answered your question please accept my answer by clicking the grey circle next to it.

Petter Myhre ( 2017-04-25 08:57:19 +0200 )editconvert to answer

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer. Do not ask a new question or reply to an answer here.

[hide preview]

Question Tools

1 follower

Stats

Asked: 2017-04-06 08:19:54 +0200

Seen: 80 times

Last updated: Apr 21