Пример #1
0
nrfx_err_t nrfx_rtc_cc_set(nrfx_rtc_t const * const p_instance,
                           uint32_t channel,
                           uint32_t val,
                           bool enable_irq)
{
    NRFX_ASSERT(m_cb[p_instance->instance_id].state != NRFX_DRV_STATE_UNINITIALIZED);
    NRFX_ASSERT(channel<p_instance->cc_channel_count);

    nrfx_err_t err_code;
    uint32_t int_mask = RTC_CHANNEL_INT_MASK(channel);
    nrf_rtc_event_t event    = RTC_CHANNEL_EVENT_ADDR(channel);

    nrf_rtc_event_disable(p_instance->p_reg, int_mask);
    nrf_rtc_int_disable(p_instance->p_reg, int_mask);

    val = RTC_WRAP(val);
    if (m_cb[p_instance->instance_id].reliable)
    {
        nrf_rtc_cc_set(p_instance->p_reg,channel,val);
        uint32_t cnt = nrf_rtc_counter_get(p_instance->p_reg);
        int32_t diff = cnt - val;
        if (cnt < val)
        {
            diff += RTC_COUNTER_COUNTER_Msk;
        }
        if (diff < m_cb[p_instance->instance_id].tick_latency)
        {
            err_code = NRFX_ERROR_TIMEOUT;
            NRFX_LOG_WARNING("Function: %s, error code: %s.",
                             __func__,
                             NRFX_LOG_ERROR_STRING_GET(err_code));
            return err_code;
        }
    }
    else
    {
        nrf_rtc_cc_set(p_instance->p_reg,channel,val);
    }

    if (enable_irq)
    {
        nrf_rtc_event_clear(p_instance->p_reg,event);
        nrf_rtc_int_enable(p_instance->p_reg, int_mask);
    }
    nrf_rtc_event_enable(p_instance->p_reg,int_mask);

    NRFX_LOG_INFO("RTC id: %d, channel enabled: %lu, compare value: %lu.",
                  p_instance->instance_id,
                  channel,
                  val);
    err_code = NRFX_SUCCESS;
    NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
    return err_code;
}
Пример #2
0
int z_clock_driver_init(struct device *device)
{
	struct device *clock;

	ARG_UNUSED(device);

	clock = device_get_binding(CONFIG_CLOCK_CONTROL_NRF_K32SRC_DRV_NAME);
	if (!clock) {
		return -1;
	}

	clock_control_on(clock, (void *)CLOCK_CONTROL_NRF_K32SRC);

	/* TODO: replace with counter driver to access RTC */
	nrf_rtc_prescaler_set(RTC, 0);
	nrf_rtc_cc_set(RTC, 0, CYC_PER_TICK);
	nrf_rtc_event_enable(RTC, RTC_EVTENSET_COMPARE0_Msk);
	nrf_rtc_int_enable(RTC, RTC_INTENSET_COMPARE0_Msk);

	/* Clear the event flag and possible pending interrupt */
	nrf_rtc_event_clear(RTC, NRF_RTC_EVENT_COMPARE_0);
	NVIC_ClearPendingIRQ(RTC1_IRQn);

	IRQ_CONNECT(RTC1_IRQn, 1, rtc1_nrf_isr, 0, 0);
	irq_enable(RTC1_IRQn);

	nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_CLEAR);
	nrf_rtc_task_trigger(RTC, NRF_RTC_TASK_START);

	if (!IS_ENABLED(TICKLESS_KERNEL)) {
		set_comparator(counter() + CYC_PER_TICK);
	}

	return 0;
}
Пример #3
0
static void AlarmStartAt(uint32_t aTargetTime, AlarmIndex aIndex)
{
    uint32_t targetCounter;
    uint32_t now;

    nrf_rtc_int_disable(RTC_INSTANCE, sChannelData[aIndex].mCompareInt);
    nrf_rtc_event_enable(RTC_INSTANCE, sChannelData[aIndex].mCompareEventMask);

    sTimerData[aIndex].mTargetTime = aTargetTime;

    targetCounter = TimeToTicks(sTimerData[aIndex].mTargetTime, aIndex);

    nrf_rtc_cc_set(RTC_INSTANCE, sChannelData[aIndex].mChannelNumber, targetCounter);

    now = AlarmGetCurrentTimeRtcProtected(aIndex);

    if (AlarmShallStrike(now, aIndex))
    {
        HandleCompareMatch(aIndex, true);
    }
    else
    {
        nrf_rtc_int_enable(RTC_INSTANCE, sChannelData[aIndex].mCompareInt);
    }
}
Пример #4
0
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
    TickType_t wakeupTime;

    /* Make sure the SysTick reload value does not overflow the counter. */
    if( xExpectedIdleTime > portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
    {
        xExpectedIdleTime = portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP;
    }
    /* Block the scheduler now */
    portDISABLE_INTERRUPTS();

    /* Stop tick events */
    nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);

    /* Configure CTC interrupt */
    wakeupTime = nrf_rtc_counter_get(portNRF_RTC_REG) + xExpectedIdleTime;
    wakeupTime &= portNRF_RTC_MAXTICKS;
    nrf_rtc_cc_set(portNRF_RTC_REG, 0, wakeupTime);
    nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0);
    nrf_rtc_int_enable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);

    if( eTaskConfirmSleepModeStatus() == eAbortSleep )
    {
        portENABLE_INTERRUPTS();
    }
    else
    {
        TickType_t xModifiableIdleTime = xExpectedIdleTime;
        configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
        if( xModifiableIdleTime > 0 )
        {
            __DSB();
#ifdef SOFTDEVICE_PRESENT
            /* With SD there is no problem with possibility of interrupt lost.
             * every interrupt is counted and the counter is processed inside
             * sd_app_evt_wait function. */
            portENABLE_INTERRUPTS();
            sd_app_evt_wait();
#else
            /* No SD -  we would just block interrupts globally.
             * BASEPRI cannot be used for that because it would prevent WFE from wake up.
             */
            __disable_irq();
            portENABLE_INTERRUPTS();
            do{
                __WFE();
            } while(0 == (NVIC->ISPR[0] | NVIC->ISPR[1]));
            __enable_irq();
#endif
        }
        configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
        portENABLE_INTERRUPTS();
    }
    // We can do operations below safely, because when we are inside vPortSuppressTicksAndSleep
    // scheduler is already suspended.
    nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);
    nrf_rtc_int_enable (portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);
}
Пример #5
0
ret_code_t nrf_drv_rtc_cc_set(nrf_drv_rtc_t const * const p_instance,
                              uint32_t channel,
                              uint32_t val,
                              bool enable_irq)
{
    ASSERT(m_cb[p_instance->instance_id].state != NRF_DRV_STATE_UNINITIALIZED);
    ASSERT(channel<p_instance->cc_channel_count);

    uint32_t int_mask = RTC_CHANNEL_INT_MASK(channel);
    nrf_rtc_event_t event    = RTC_CHANNEL_EVENT_ADDR(channel);

    nrf_rtc_event_disable(p_instance->p_reg, int_mask);
    nrf_rtc_int_disable(p_instance->p_reg, int_mask);

    val = RTC_WRAP(val);
    if (m_cb[p_instance->instance_id].reliable)
    {
        nrf_rtc_cc_set(p_instance->p_reg,channel,val);
        uint32_t cnt = nrf_rtc_counter_get(p_instance->p_reg);
        int32_t diff = cnt - val;
        if (cnt < val)
        {
            diff += RTC_COUNTER_COUNTER_Msk;
        }
        if (diff < m_cb[p_instance->instance_id].tick_latency)
        {
            return NRF_ERROR_TIMEOUT;
        }
    }
    else
    {
        nrf_rtc_cc_set(p_instance->p_reg,channel,val);
    }

    if (enable_irq)
    {
        nrf_rtc_event_clear(p_instance->p_reg,event);
        nrf_rtc_int_enable(p_instance->p_reg, int_mask);
    }
    nrf_rtc_event_enable(p_instance->p_reg,int_mask);

    return NRF_SUCCESS;
}
Пример #6
0
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
    TickType_t wakeupTime;

    /* Make sure the SysTick reload value does not overflow the counter. */
    if( xExpectedIdleTime > portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
    {
        xExpectedIdleTime = portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP;
    }
    /* Block the scheduler now */
    portDISABLE_INTERRUPTS();

    /* Stop tick events */
    nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);

    /* Configure CTC interrupt */
    wakeupTime = nrf_rtc_counter_get(portNRF_RTC_REG) + xExpectedIdleTime;
    wakeupTime &= portNRF_RTC_MAXTICKS;
    nrf_rtc_cc_set(portNRF_RTC_REG, 0, wakeupTime);
    nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0);
    nrf_rtc_int_enable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);

    if( eTaskConfirmSleepModeStatus() == eAbortSleep )
    {
        portENABLE_INTERRUPTS();
    }
    else
    {
        TickType_t xModifiableIdleTime = xExpectedIdleTime;
        configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
        if( xModifiableIdleTime > 0 )
        {
            __DSB();
            do{
                __WFE();
            } while(0 == (NVIC->ISPR[0]));
        }
        configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
        portENABLE_INTERRUPTS();
    }
    // We can do operations below safely, because when we are inside vPortSuppressTicksAndSleep
    // scheduler is already suspended.
    nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);
    nrf_rtc_int_enable (portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);
}
Пример #7
0
void common_rtc_set_interrupt(uint32_t us_timestamp, uint32_t cc_channel,
                              uint32_t int_mask)
{
    // The internal counter is clocked with a frequency that cannot be easily
    // multiplied to 1 MHz, therefore besides the translation of values
    // (microsecond <-> ticks) a special care of overflows handling must be
    // taken. Here the 32-bit timestamp value is complemented with information
    // about current the system up time of (ticks + number of overflows of tick
    // counter on upper bits, converted to microseconds), and such 64-bit value
    // is then translated to counter ticks. Finally, the lower 24 bits of thus
    // calculated value is written to the counter compare register to prepare
    // the interrupt generation.
    uint64_t current_time64 = common_rtc_64bit_us_get();
    // [add upper 32 bits from the current time to the timestamp value]
    uint64_t timestamp64 = us_timestamp +
                           (current_time64 & ~(uint64_t)0xFFFFFFFF);

    // [if the original timestamp value happens to be after the 32 bit counter
    //  of microsends overflows, correct the upper 32 bits accordingly]
    if (us_timestamp < (uint32_t)(current_time64 & 0xFFFFFFFF))
    {
        timestamp64 += ((uint64_t)1 << 32);
    }
    // [microseconds -> ticks, always round the result up to avoid too early
    //  interrupt generation]
    uint32_t compare_value =
        (uint32_t)CEIL_DIV((timestamp64) * RTC_INPUT_FREQ, 1000000);

    // The COMPARE event occurs when the value in compare register is N and
    // the counter value changes from N-1 to N. Therefore, the minimal safe
    // difference between the compare value to be set and the current counter
    // value is 2 ticks. This guarantees that the compare trigger is properly
    // setup before the compare condition occurs.
    uint32_t closest_safe_compare = common_rtc_32bit_ticks_get() + 2;
    if ((int)(compare_value - closest_safe_compare) <= 0)
    {
        compare_value = closest_safe_compare;
    }

    nrf_rtc_cc_set(COMMON_RTC_INSTANCE, cc_channel, RTC_WRAP(compare_value));
    nrf_rtc_event_enable(COMMON_RTC_INSTANCE, int_mask);
}
Пример #8
0
int _sys_clock_driver_init(struct device *device)
{
	struct device *clock;

	ARG_UNUSED(device);

	clock = device_get_binding(CONFIG_CLOCK_CONTROL_NRF5_K32SRC_DRV_NAME);
	if (!clock) {
		return -1;
	}

	clock_control_on(clock, (void *)CLOCK_CONTROL_NRF5_K32SRC);

	rtc_past = 0;

#ifdef CONFIG_TICKLESS_IDLE
	expected_sys_ticks = 1;
#endif /* CONFIG_TICKLESS_IDLE */

	/* TODO: replace with counter driver to access RTC */
	SYS_CLOCK_RTC->PRESCALER = 0;
	nrf_rtc_cc_set(SYS_CLOCK_RTC, RTC_CC_IDX, sys_clock_hw_cycles_per_tick);
	nrf_rtc_event_enable(SYS_CLOCK_RTC, RTC_EVTENSET_COMPARE0_Msk);
	nrf_rtc_int_enable(SYS_CLOCK_RTC, RTC_INTENSET_COMPARE0_Msk);

	/* Clear the event flag and possible pending interrupt */
	RTC_CC_EVENT = 0;
	NVIC_ClearPendingIRQ(NRF5_IRQ_RTC1_IRQn);

	IRQ_CONNECT(NRF5_IRQ_RTC1_IRQn, 1, rtc1_nrf5_isr, 0, 0);
	irq_enable(NRF5_IRQ_RTC1_IRQn);

	nrf_rtc_task_trigger(SYS_CLOCK_RTC, NRF_RTC_TASK_CLEAR);
	nrf_rtc_task_trigger(SYS_CLOCK_RTC, NRF_RTC_TASK_START);

	return 0;
}
Пример #9
0
/*
 * Set RTC Counter Compare (CC) register to a given value in RTC ticks.
 */
static void rtc_compare_set(u32_t rtc_ticks)
{
	u32_t rtc_now;

	/* Try to set CC value. We assume the procedure is always successful. */
	nrf_rtc_cc_set(SYS_CLOCK_RTC, RTC_CC_IDX, rtc_ticks);
	rtc_now = RTC_COUNTER;

	/* The following checks if the CC register was set to a valid value.
	 * The first test checks if the distance between the current RTC counter
	 * and the value (in the future) set in the CC register is too small to
	 * guarantee a compare event being triggered.
	 * The second test checks if the current RTC counter is higher than the
	 * value written to the CC register, i.e. the CC value is in the past,
	 * by checking if the unsigned subtraction wraps around.
	 * If either of the above are true then instead of waiting for the CC
	 * event to trigger in the form of an interrupt, trigger it directly
	 * using the NVIC.
	 */
	if ((((rtc_ticks - rtc_now) & RTC_MASK) < RTC_MIN_DELTA) ||
	    (((rtc_ticks - rtc_now) & RTC_MASK) > RTC_HALF)) {
		NVIC_SetPendingIRQ(NRF5_IRQ_RTC1_IRQn);
	}
}
Пример #10
0
static inline void set_comparator(u32_t cyc)
{
	nrf_rtc_cc_set(RTC, 0, cyc);
}
Пример #11
0
void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
{
    /*
     * Implementation note:
     *
     * To help debugging the option configUSE_TICKLESS_IDLE_SIMPLE_DEBUG was presented.
     * This option would make sure that even if program execution was stopped inside
     * this function no more than expected number of ticks would be skipped.
     *
     * Normally RTC works all the time even if firmware execution was stopped
     * and that may lead to skipping too much of ticks.
     */
    TickType_t enterTime;

    /* Make sure the SysTick reload value does not overflow the counter. */
    if ( xExpectedIdleTime > portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
    {
        xExpectedIdleTime = portNRF_RTC_MAXTICKS - configEXPECTED_IDLE_TIME_BEFORE_SLEEP;
    }
    /* Block the scheduler now */
    portDISABLE_INTERRUPTS();

    /* Configure CTC interrupt */
    enterTime = nrf_rtc_counter_get(portNRF_RTC_REG);

    if ( eTaskConfirmSleepModeStatus() == eAbortSleep )
    {
        portENABLE_INTERRUPTS();
    }
    else
    {
        TickType_t xModifiableIdleTime;
        TickType_t wakeupTime = (enterTime + xExpectedIdleTime) & portNRF_RTC_MAXTICKS;

        /* Stop tick events */
        nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);

        /* Configure CTC interrupt */
        nrf_rtc_cc_set(portNRF_RTC_REG, 0, wakeupTime);
        nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_COMPARE_0);
        nrf_rtc_int_enable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);

        __DSB();

        /* Sleep until something happens.  configPRE_SLEEP_PROCESSING() can
         * set its parameter to 0 to indicate that its implementation contains
         * its own wait for interrupt or wait for event instruction, and so wfi
         * should not be executed again.  However, the original expected idle
         * time variable must remain unmodified, so a copy is taken. */
        xModifiableIdleTime = xExpectedIdleTime;
        configPRE_SLEEP_PROCESSING( xModifiableIdleTime );
        if ( xModifiableIdleTime > 0 )
        {
#ifdef SOFTDEVICE_PRESENT
            sd_app_evt_wait();
#else
            do{
                __WFE();
            } while (0 == (NVIC->ISPR[0]));
#endif
        }
        configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
        nrf_rtc_int_disable(portNRF_RTC_REG, NRF_RTC_INT_COMPARE0_MASK);
        portENABLE_INTERRUPTS();

        /* Correct the system ticks */
        portENTER_CRITICAL();
        {
            TickType_t diff;
            TickType_t hwTicks     = nrf_rtc_counter_get(portNRF_RTC_REG);
            nrf_rtc_event_clear(portNRF_RTC_REG, NRF_RTC_EVENT_TICK);
            nrf_rtc_int_enable (portNRF_RTC_REG, NRF_RTC_INT_TICK_MASK);

            if(enterTime > hwTicks)
            {
                hwTicks += portNRF_RTC_MAXTICKS + 1U;
            }

            diff = (hwTicks - enterTime);
            if((configUSE_TICKLESS_IDLE_SIMPLE_DEBUG) && (diff > xExpectedIdleTime))
            {
                diff = xExpectedIdleTime;
            }

            if (diff > 0)
            {
                vTaskStepTick(diff);
            }
        }
        portEXIT_CRITICAL();
    }
}