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

Softdevice timer

Hey guys,

I'm working with SES, nRF52832 and SDK14.2.0.

I have a timing problem and would like to describe the problem from the beginning.

I have a 1-wire temperature sensor that is read by the slave and then the slave sends the sensor data to the master via BLE every second. (That is my goal.)

1) First I measured the "temperature conversion time" of the sensor with the project: peripheral / uart, which I modified with a timer for the interval transmission (of 1 second) and with a timer for measuring the time.

Timer for sending in intervals:

...

/**< Driver instance for timer 1 */
const nrf_drv_timer_t TIMER_SEND_DATA = NRF_DRV_TIMER_INSTANCE(1);


/**
 * @brief Handler for timer events.
 */
 void timer_event_handler(nrf_timer_event_t event_type, void* p_context)
{
    switch (event_type)
    {
        case NRF_TIMER_EVENT_COMPARE1:
            send_telegram();                //with temperature data
            break;

        default:
            //Do nothing.
            break;
    }
}


/**
 * @brief Init for timer events.
 */
static void timer_SendData_init()
{
    uint32_t time_ms = 1000;                                            /**< Time(in miliseconds) between consecutive compare events */
    uint32_t time_ticks;
    uint32_t err_code = NRF_SUCCESS;
    
    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    err_code = nrf_drv_timer_init(&TIMER_SEND_DATA, &timer_cfg, timer_event_handler);
    APP_ERROR_CHECK(err_code);

    time_ticks = nrf_drv_timer_ms_to_ticks(&TIMER_SEND_DATA, time_ms);

    nrf_drv_timer_extended_compare(
         &TIMER_SEND_DATA, NRF_TIMER_CC_CHANNEL1, time_ticks, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, true);
    nrf_drv_timer_enable(&TIMER_SEND_DATA);
}



Timer for measuring:

///////Function to measure time

/**< Temperature request and read */
int OneWire_Read_Temperature(void)
{
    uint32_t captured_value = 0;

    .....
    
    /**< Start of the time measurement  */
    NRF_TIMER2->TASKS_CLEAR = 1;
    NRF_TIMER2->TASKS_START = 1;

    /**< DS18B20 store thermal data in the scratchpad (2-byte temp register) */
    while (! OneWire_Read_Byte());                        /**< Sensor respond by transmitting a 0 while temperatur conversion is in progress and a 1 when conversion is done
                                                           * after storing the Sensor returns to its low power idle state */
    
    /**< End of the time measurement */
    NRF_TIMER2->TASKS_CAPTURE[1] = 1;
    captured_value = NRF_TIMER2->CC[1];
    NRF_TIMER2->TASKS_STOP = 1;

    printf("Cycles: %u. ", captured_value);               /**< Print captured value in cycles; 1 cycle = 1 us */
}


/**
 * @brief Init the measurement.
 */
void Timer_Timing_init(void)
{
    NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_32Bit;    /**< Timer range: 0 to 4294 secondes */
    NRF_TIMER2->SHORTS = TIMER_SHORTS_COMPARE2_CLEAR_Enabled << TIMER_SHORTS_COMPARE2_CLEAR_Pos| TIMER_SHORTS_COMPARE2_STOP_Enabled << TIMER_SHORTS_COMPARE2_STOP_Pos;  /**< Enable clear and stop timer */
    NRF_TIMER2->PRESCALER = 4;                            /**< Prescaler = 4 -> f(TIMER) = 16MHz / (2^PRESCALER) = 1MHz -> t(TIMER) = 1us (1 cycle = 1us) */
}

And I get the measured time around 702 milliseconds (with small deviations in the microsecond range). And this value is ok.

When I measure all the code that is triggered by the timer (case NRF_TIMER_EVENT_COMPARE1), I get a measured value of approx. 720 milliseconds.

Everything fits up to here.

2) Now I would like to send the sensor data via BLE and have selected the following programs for the slave and the master:

Slave: ble_peripheral/ble_app_uart

Master: ble_central/ble_app_uart_c

I set the timer for sending after every second exactly as in the "peripheral / uart" project. I have installed the timer for measuring in "case NRF_NRF_TIMER_EVENT_COMPARE1":

/**
 * @brief Handler for timer events.
 */
void timer_event_handler(nrf_timer_event_t event_type, void* p_context)
{   
    int RetVal;
    uint32_t captured_value = 0;
    switch (event_type)
    {
        case NRF_TIMER_EVENT_COMPARE1:
            
        
            /**< Start of the runtime measurement */
            NRF_TIMER2->TASKS_CLEAR = 1;
            NRF_TIMER2->TASKS_START = 1;
            RetVal = send_temperature();              /**< Function call to send the temperature value to the master */ 
            if (RetVal != READ_TEMP_SUCCESSFUL)       /**< When an error occurs: report it */
            {
                printf("ERROR: %x \r\n", RetVal);
            }

            NRF_TIMER2->TASKS_CAPTURE[1] = 1;
            captured_value = NRF_TIMER2->CC[1];
            NRF_TIMER2->TASKS_STOP = 1;
            printf("Cycles: %u. ", captured_value);               /**< Print captured value in cycles; 1 cycle = 1 us */

            
            break;
        default:
            //Do nothing.
            break;
    }
}

But here I get totally random values ​​like: 140.000 ticks, 69.000 ticks or 12.000 ticks, although the temperature conversion alone takes about 702.000 ticks (702 milliseconds). Is that because of the softdevice (ble)? If so, what can I change? I'm a bit baffled here...

For this reason, I configured the measurement timer in the master-program in "ble_nus_c_evt_handler":

/**@brief Callback handling NUS Client events.
 *
 * @details This function is called to notify the application of NUS client events.
 *
 * @param[in]   p_ble_nus_c   NUS Client Handle. This identifies the NUS client
 * @param[in]   p_ble_nus_evt Pointer to the NUS Client event.
 */

/**@snippet [Handling events from the ble_nus_c module] */
static void ble_nus_c_evt_handler(ble_nus_c_t * p_ble_nus_c, ble_nus_c_evt_t const * p_ble_nus_evt)
{
    ret_code_t err_code;
    uint32_t captured_value = 0;

    switch (p_ble_nus_evt->evt_type)
    {
        ....

        case BLE_NUS_C_EVT_NUS_TX_EVT:
            /**< End of the runtime measurement */
            NRF_TIMER2->TASKS_CAPTURE[1] = 1;
            captured_value = NRF_TIMER2->CC[1];
            NRF_TIMER2->TASKS_STOP = 1;
            printf("Cycles: %u. ", captured_value);               /**< Print captured value in cycles; 1 cycle = 1 us */

            /**< Start of the runtime measurement */
            NRF_TIMER2->TASKS_CLEAR = 1;
            NRF_TIMER2->TASKS_START = 1;

            ble_nus_chars_received_uart_print(p_ble_nus_evt->p_data, p_ble_nus_evt->data_len);

            break;

            ....
    }
}
/**@snippet [Handling events from the ble_nus_c module] */

Here I get values ​​in 1 second intervals, but the values ​​fluctuate very strongly (up to 200 ms) ... That means the master gets values ​​in an interval between 0.8 and 1.2 seconds, but I need an accurate interval of 1 second... Does anyone know what I can do? I would be very happy about any help ..

Best regards,

Christoph

Parents
  • Hi Christoph,

    I guess the problem here is that you are doing all this in the connected state which includes a bit of softdevice activity which has higher priority than any other activity in your application. 

    First suggestion is to change your timer irq priority which is inside NRF_DRV_TIMER_DEFAULT_CONFIG. The default one I think is using TIMER_DEFAULT_CONFIG_IRQ_PRIORITY which is 6 which is a bit low. You can change that to app priority 3 for example.

    Here I get values ​​in 1 second intervals, but the values ​​fluctuate very strongly (up to 200 ms) ... That means the master gets values ​​in an interval between 0.8 and 1.2 seconds,

    The slave program won't be able to transmit exactly after 1 second as SD might steal the CPU for some pre processing of RADIO at that exact time. We cannot guarantee that the timer callbacks are called without any delays when they are used alongside the SD while there is a BLE connection. That probably is the reason that you see few milliseconds delay on when you are transmitting the byte in the slave end. And the byte is not guaranteed to be transmitted as soon as you call the BLE send API. The softdevice needs to know if there is enough connection event slot left to be able to send the data or it need to wait until the next connection event started.

    Out of curiosity, why can't your master sustain a delay of few milliseconds in getting the temperature sensor data. What application is this that requires the temperature to be sent exactly at 1 second without any delays? Just trying to understand.

  • Hey Susheel,

    thank you for your reply.

    I guess the problem here is that you are doing all this in the connected state which includes a bit of softdevice activity which has higher priority than any other activity in your application. 

    Thats right.  I measure the time (timer 2) and run a timer (timer 1 for sending every second) in the connected state, whereby timer 2 only shows random values ​​on the slave side and shows usable values ​​on the master side (when programmed on master side). First I try to measure the temperature conversion time with SD when SD is not connected. (Because I only measured the time in the peripheral example, i.e. in a project without a soft device.)

    Second, i will change the timer irq priority as you recommended. And then I measure again.

    The slave program won't be able to transmit exactly after 1 second as SD might steal the CPU for some pre processing of RADIO at that exact time. We cannot guarantee that the timer callbacks are called without any delays when they are used alongside the SD while there is a BLE connection. That probably is the reason that you see few milliseconds delay on when you are transmitting the byte in the slave end. And the byte is not guaranteed to be transmitted as soon as you call the BLE send API. The softdevice needs to know if there is enough connection event slot left to be able to send the data or it need to wait until the next connection event started.

    First of all it's good to know where the problem is (SD). Do you know how much time the SD needs to preprocess the RADIO? And maybe there are ways to increase accuracy?

    Out of curiosity, why can't your master sustain a delay of few milliseconds in getting the temperature sensor data. What application is this that requires the temperature to be sent exactly at 1 second without any delays? Just trying to understand.

    For your understanding: We have a device in which the temperature sensor and our slave are loacted. The slave should send a measured value to the master every one second (as precisely and constantly as possible). On the one hand the master should store the temperature value and show it on the display on the other.

    Do you know how to create a time stamp on the slave?

    Best regards,

    Christoph

  • Christoph_I said:
    First of all it's good to know where the problem is (SD). Do you know how much time the SD needs to preprocess the RADIO? And maybe there are ways to increase accuracy?

     Christoph, these pages are very useful for you to read to get understanding of the processor usage by the SD at different instances. One way to increase the accuracy is to use priority  2 or 3 for the timer (configurable in sdk_config.h) so that Bluetooth host does not mask timer callbacks (the problem with this is that at this higher priority callabcks you cannot call any SVC calls, that is you cannot call any softdevice API that looks like sd_xxxx()). The activity in the link layer will still have higher priority since it operates with interrupt priority 0 (highest). 

    Christoph_I said:
    Do you know how to create a time stamp on the slave?

    There are many ways to generate a software timestamp based on the underlying hardware RTC. If you search the devzone you will find many such threads where many users achieved it in a different way, one such example is this one. 

  • Hey Susheel,

    I have recommended your first answer as "suggest answer". I would prefer not to close this thread yet if there are other problems later on (because I currently have other projects in parallel). Is that ok for you?

    Best regards,

    Christoph

  • Christoph, 

    glad to hear that the answer helped. If you have related questions to this one, then you can reopen the thread again to ask more. For a different questions, please open a new ticket. This would help keep this thread clean and help others find relevant information easier. So I am marking this thread as verified and would be very happy to help you in your ongoing project questions in newer threads. There is no limit on on many threads you can create if you need assistance.

Reply
  • Christoph, 

    glad to hear that the answer helped. If you have related questions to this one, then you can reopen the thread again to ask more. For a different questions, please open a new ticket. This would help keep this thread clean and help others find relevant information easier. So I am marking this thread as verified and would be very happy to help you in your ongoing project questions in newer threads. There is no limit on on many threads you can create if you need assistance.

Children
No Data
Related