Linux preempt-rt

Check our new training course

Real-Time Linux with PREEMPT_RT

Check our new training course
with Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/* Copyright (c) 2018, Nordic Semiconductor ASA
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright notice, this
 *      list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *
 *   3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *      contributors may be used to endorse or promote products derived from
 *      this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef NRF_802154_UTILS_H__
#define NRF_802154_UTILS_H__

#include <assert.h>
#include <stdint.h>
#include "nrf.h"

/**
 * @defgroup nrf_802154_utils Utils definitions used in the 802.15.4 driver.
 * @{
 * @ingroup nrf_802154
 * @brief Definitions of utils used in the 802.15.4 driver.
 */

/**@brief RTC clock frequency. */
#define NRF_802154_RTC_FREQUENCY               32768UL

/**@brief Defines number of microseconds in one second. */
#define NRF_802154_US_PER_S                    1000000ULL

/**@brief Number of microseconds in one RTC tick. (rounded up) */
#define NRF_802154_US_PER_TICK                 NRF_802154_RTC_TICKS_TO_US(1)

/**@brief Number of bits to shift RTC_FREQUENCY and US_PER_S to achieve division by greatest common divisor. */
#define NRF_802154_FREQUENCY_US_PER_S_GCD_BITS 6

/**@brief Ceil division helper */
#define NRF_802154_DIVIDE_AND_CEIL(A, B)       (((A) + (B)-1) / (B))

/**@brief RTC ticks to us conversion. */
#define NRF_802154_RTC_TICKS_TO_US(ticks)                                          \
    NRF_802154_DIVIDE_AND_CEIL(                                                    \
        (ticks) * (NRF_802154_US_PER_S >> NRF_802154_FREQUENCY_US_PER_S_GCD_BITS), \
        (NRF_802154_RTC_FREQUENCY >> NRF_802154_FREQUENCY_US_PER_S_GCD_BITS))

static inline uint64_t NRF_802154_US_TO_RTC_TICKS(uint64_t time)
{
    uint64_t t1, u1;
    uint64_t result;

    /* The required range for time is [0..315360000000000], and the calculation below are
       verified to work within broader range [0...2^49 ~ 17 years]

       This first step in the calculation is to find out how many units
       of 15625 us there are in the input_us, because 512 RTC units
       corresponds _exactly_ to 15625 us. The calculation we want to do is therefore
       t1 = time / 15625, but division is slow and therefore we want to calculate
       t1 = time * k instead. The constant k is 1/15625 shifted up by as many bits
       as we can without causing overflow during the calculation.

       49 bits are needed to store the maximum value that time can have, and the
       lowest 13 bits in that value can be shifted away because a minimum of 14 bits
       are needed to store the divisor.

       This means that time can be reduced to 49 - 13 = 36 bits to make space
       for k.

       The most suitable number of shift for the value 1 / 15625 = 0.000064
       (binary 0.00000000000001000011000110111101111...) is 41, because that results
       in a 28 bits number that does not cause overflow in the multiplication.

       (2^41)/15625) is equal to 0x8637bd0, and is written in hexadecimal representation
       to show the bit width of the number. Shifting is limited to 41 bits because:
         1  The time uses up to 49 bits, and
         2) The time can only be shifted down 13 bits to avoid shifting away
            a full unit of 15625 microseconds, and
         3) The maximum value of the calculation would otherwise overflow (i.e.
            (315360000000000 >> 13) * 0x8637bd0 = 0x4b300bfcd0aefde0, would no longer be less than
            0Xffffffffffffffff).

       There is a possible loss of precision so that t1 will be up to 93*15625 _smaller_
       than the accurate number. This is taken into account in the next step.
     */

    t1     = ((time >> 13) * 0x8637bd0) >> 28; // ((time >> 13) * (2^41 / 15625)) >> (41 - 13)
    result = t1 * 512;
    t1     = time - t1 * 15625;

    /* This second step of the calculation is to find out how many RTC units there are
       still left in the remaining microseconds.

       (2^56)/15625) is equal to 0x431bde82d7b, and is written in hexadecimal representation
       to show the bit width of the number. Shifting 56 bits is determined by the worst
       case value of t1. The constant is selected by using the same methodology as in the
       first step of the calculation above.

       The possible loss of precision in the calculation above can make t1 93*15625 lower
       than it should have been here. The worst case found is that t1 can be 1453125, and
       therefore there is no overflow in the calculation
       1453125 * 0x431bde82d7b = 0x5cfffffffff76627 (i.e. it is less than 0xffffffffffffffff).

       15625 below is the binary representation of 30.51757813 (11110.100001001)
       scaled up by 2^9, and the calculation below are therefore using that scale.

       Rounding up to the nearest RTC tick is done by adding the value of the least
       significant bits of the fraction (i.e. adding the value of bits 1..47 of the scaled
       up timer unit size (2^47)) to the calculated value before scaling the final
       value down to RTC ticks.*/

    // ceil((time * (2^56 / 15625)) >> (56 - 9))
    assert(t1 <= 1453125);
    u1   = (t1 * 0x431bde82d7b); // (time * (2^56 / 15625))
    u1  += 0x7fffffffffff;       // round up
    u1 >>= 47;                   // ceil(u1 >> (56 - 9))

    result += u1;

    return result;
}

/**@brief Checks if the provided interrupt is currently enabled.
 *
 * @note This function is valid only for ARM Cortex-M4 core.
 *
 * @params IRQn  Interrupt number.
 *
 * @returns  Zero if interrupt is disabled, non-zero value otherwise.
 */
static inline uint32_t nrf_is_nvic_irq_enabled(IRQn_Type IRQn)
{
    return (NVIC->ISER[(((uint32_t)(int32_t)IRQn) >> 5UL)]) &
           ((uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)));
}

/**
 *@}
 **/

#endif // NRF_802154_UTILS_H__