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

Removing Connection Parameter Negotiation BLE library from ble_peripheral ble_app_uart example app

Hello ...

Implementing an app for both nRF51822 and nRF52810 and need a long-term clock with 100 Hz counter frequency to timestamp sensor events. By long-term, I mean at least 5 hours. I'm using TIMER1 and TIMER2 for other timing functions, so that leaves me with RTC0 or RTC1. Need use concurrent with BLE S110 (nRF51) or S112 (nRF52).

I understand RTC0 is used by the SoftDevice and therefore cannot be used. To develop my app I started with the example ble_peripheral/ble_app_uart and have been modifying/trimming. I'm testing on an nRF52 dev kit with nRF52810 emulation. It appears that ble_conn_params.c (Connection Parameters Negotiation library) uses app_timer library (app_timer_create() in ble_conn_params_init(), app_timer_start() in conn_params_negotiation(), and app_timer_stop() in on_disconnect()), which uses RTC1.

A simple solution would be to use RTC1 with prescaler of 327 which would give me 100 Hz resolution and 46+ hours before overflow.

It seems like ble_conn_params.c uses app_timer/RTC1 for connection parameter negotiation and only under erroneous conditions (if (!p_instance->params_ok)). I've found that once a BLE connection has been established, RTC1 is stopped and its counter value is 0, and remains so.

Can I access/control RTC1 directly after BLE connection is established? If yes, then I can set its prescaler to 327 (NRF_RTC1->PRESCALER = 327), start it (NRF_RTC1->TASK_START), and then use NRF_RTC1->COUNTER to read the value to get the number of 10.009574 ms ticks since RTC1 started. After disconnecting BLE, I would stop RTC1 and set its prescaler back to 0. Reasonable? I've implemented this and it appears to work well but I'm concerned about the risk of manipulating RTC1 while ble_conn_params.c is using app_timer/RTC1.

This post suggests it's possible to avoid using the Connection Parameters Negotiation library to avoid the need for/use of app_timer, which would free up RTC1 for exclusive use by my app. I would appreciate any guidance in how to do this. I'm new to Nordic SDK.

I'm also planning to implement RTC synchronization across multiple nRF5 devices using this blog post.

Thanks in advance for any guidance.

Tim

Parents
  • Hi,

     

    I've implemented this and it appears to work well but I'm concerned about the risk of manipulating RTC1 while ble_conn_params.c is using app_timer/RTC1.

     The RTC1 peripheral is only used by app_timer, and if you, in your application, have total control over when the app_timer uses it, I do not see any reasons why you shouldn't go forward with that.

    If you can use the same prescaler in app_timer as in your application, you could also modify app_timer.c (irq handler) to check other events than EVENTS_COMPARE[0], as app_timer only uses CC[0] to handle its own queue, so if you ensure that app_timer newer stops the RTC, and you modify the irq-handler; you can use those other CC instances freely.

    That being said; If you have a solution that already works, I wouldn't change it.

     

    Kind regards,

    Håkon

  • I thought I had a solution for this, but need to revisit.

    Experiencing an intermittent issue whereby somehow RTC1's prescaler is being set to 0. My app was built by starting with ble_app_uart and removing uart and customizing. Here's how my app currently utilizes RTC1:

    1) Following connection between BLE peripheral and central (ble_evt_handler(..) receives BLE_GAP_EVT_CONNECTED in p_ble_evt->header.evt_id), peripheral and central exchange a bit of data (nus_data_handler(..) to receive from central, ble_nus_data_send(..) to send to central).

    2) At this point my app assumes that ble_conn_params.c is done using app_timer/RTC1, and proceeds to set up and start RTC1 with prescaler 255:

    NRF_RTC1->TASKS_STOP = 1;   // Stop RTC1
    NRF_RTC1->TASKS_CLEAR = 1;  // Clear RTC1
    NRF_RTC1->PRESCALER = 255;  // Set RTC1 prescaler
    NRF_RTC1->TASKS_START = 1;  // Start RTC1
    
    NVIC_ClearPendingIRQ(RTC1_IRQn);
    NVIC_DisableIRQ(RTC1_IRQn);
    
    uint16_t current_prescaler = NRF_RTC1->PRESCALER;
    NRF_LOG_INFO("current_prescaler %d", current_prescaler);

    Sometimes NRF_LOG_INFO shows current_prescaler to be 255, sometimes 0. It seems that even at the point a central/peripheral connection has been established, ble_conn_params.c may still be using app_timer/RTC1. Even though my app sets prescaler to 255, app_timer might be setting it back to 0?

    Is there a way I can know for sure when ble_conn_params.c is done with app_timer/RTC1 so my app can safely use RTC1?

    I guess another option is to not use ble_conn_parameters/app_timer, but I don't know how to do that. If simple, I'd appreciate the code to do so.

    Many thanks,

    Tim

Reply
  • I thought I had a solution for this, but need to revisit.

    Experiencing an intermittent issue whereby somehow RTC1's prescaler is being set to 0. My app was built by starting with ble_app_uart and removing uart and customizing. Here's how my app currently utilizes RTC1:

    1) Following connection between BLE peripheral and central (ble_evt_handler(..) receives BLE_GAP_EVT_CONNECTED in p_ble_evt->header.evt_id), peripheral and central exchange a bit of data (nus_data_handler(..) to receive from central, ble_nus_data_send(..) to send to central).

    2) At this point my app assumes that ble_conn_params.c is done using app_timer/RTC1, and proceeds to set up and start RTC1 with prescaler 255:

    NRF_RTC1->TASKS_STOP = 1;   // Stop RTC1
    NRF_RTC1->TASKS_CLEAR = 1;  // Clear RTC1
    NRF_RTC1->PRESCALER = 255;  // Set RTC1 prescaler
    NRF_RTC1->TASKS_START = 1;  // Start RTC1
    
    NVIC_ClearPendingIRQ(RTC1_IRQn);
    NVIC_DisableIRQ(RTC1_IRQn);
    
    uint16_t current_prescaler = NRF_RTC1->PRESCALER;
    NRF_LOG_INFO("current_prescaler %d", current_prescaler);

    Sometimes NRF_LOG_INFO shows current_prescaler to be 255, sometimes 0. It seems that even at the point a central/peripheral connection has been established, ble_conn_params.c may still be using app_timer/RTC1. Even though my app sets prescaler to 255, app_timer might be setting it back to 0?

    Is there a way I can know for sure when ble_conn_params.c is done with app_timer/RTC1 so my app can safely use RTC1?

    I guess another option is to not use ble_conn_parameters/app_timer, but I don't know how to do that. If simple, I'd appreciate the code to do so.

    Many thanks,

    Tim

Children
  • I think the simplest way would be to implement your own reduced version of app_timer, and replace the calls to app_timer_start/stop in ble_conn_parameters with your own functions. Then you'd be in complete control over RTC1.

    If it is only the conn_params -module that needs app_timer, then you could even restrict your implementation to only have one timeout running at a time.

  • Thanks mrono. I agree, somehow writing my own app_timer would be ideal. I'm new to low-level BLE and Nordic SDK and do not understand ble_conn_params.c well enough to safely do this. I've noticed that on the occasions where PRESCALER is 0 after I set it to 255, about 3 seconds later app_timer's RTC1 interrupt routine (RTC1_IRQHandler()) is called. This, I think, suggests that following successful connection between central and peripheral, a timer created by ble_conn_params.c is still running and a timeout or CC event occurs.

    I'd be grateful for any guidance on either 1) removing use of ble_conn_params.c and implementing connection parameter negotiation myself (and hence removing its dependence on RTC1, or at least knowing how it uses RTC1 so I can be sure my app's use of it doesn't interfere (or vice versa), or, as you say, 2) implement my own reduced version of app_timer. How to go about that?

    Appreciate any guidance. Many thanks,

    Tim

  • A bit more info ...

    If I add nrf_delay_ms(50) after NRF_RTC1->TASKS_STOP=1 and before NRF_RTC1->PRESCALER=255, it appears that the prescaler is set correctly every time. Still, though, I'm concerned about using RTC1 before ble_conn_params.c/app_timer have finished using it.

    Thx!
    Tim

Related