<commit_before>/*
 * Copyright (C) 2014 <NAME> <<EMAIL>>
 */

#include <uavcan_stm32/clock.hpp>
#include <uavcan_stm32/thread.hpp>
#include "internal.hpp"

#if UAVCAN_STM32_TIMER_NUMBER

#include <cassert>
#include <cmath>

/*
 * Timer instance
 */
# if (UAVCAN_STM32_CHIBIOS && CH_KERNEL_MAJOR == 2) || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS
#  define TIMX                    UAVCAN_STM32_GLUE2(TIM, UAVCAN_STM32_TIMER_NUMBER)
#  define TIMX_IRQn               UAVCAN_STM32_GLUE3(TIM, UAVCAN_STM32_TIMER_NUMBER, _IRQn)
#  define TIMX_INPUT_CLOCK        STM32_TIMCLK1
# endif

# if (UAVCAN_STM32_CHIBIOS && (CH_KERNEL_MAJOR == 3 || CH_KERNEL_MAJOR == 4 || CH_KERNEL_MAJOR == 5))
#  define TIMX                    UAVCAN_STM32_GLUE2(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER)
#  define TIMX_IRQn               UAVCAN_STM32_GLUE3(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER, _NUMBER)
#  define TIMX_IRQHandler         UAVCAN_STM32_GLUE3(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER, _HANDLER)
#  define TIMX_INPUT_CLOCK        STM32_TIMCLK1
# else
#  define TIMX_IRQHandler         UAVCAN_STM32_GLUE3(TIM, UAVCAN_STM32_TIMER_NUMBER, _IRQHandler)
# endif

# if UAVCAN_STM32_NUTTX
#  define TIMX                    UAVCAN_STM32_GLUE3(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER, _BASE)
#  define  TMR_REG(o)              (TIMX + (o))
#  define TIMX_INPUT_CLOCK         UAVCAN_STM32_GLUE3(STM32_APB1_TIM, UAVCAN_STM32_TIMER_NUMBER, _CLKIN)

#  define TIMX_IRQn                UAVCAN_STM32_GLUE2(STM32_IRQ_TIM, UAVCAN_STM32_TIMER_NUMBER)
# endif

# if UAVCAN_STM32_TIMER_NUMBER >= 2 && UAVCAN_STM32_TIMER_NUMBER <= 7
#  define TIMX_RCC_ENR           RCC->APB1ENR
#  define TIMX_RCC_RSTR          RCC->APB1RSTR
#  define TIMX_RCC_ENR_MASK      UAVCAN_STM32_GLUE3(RCC_APB1ENR_TIM,  UAVCAN_STM32_TIMER_NUMBER, EN)
#  define TIMX_RCC_RSTR_MASK     UAVCAN_STM32_GLUE3(RCC_APB1RSTR_TIM, UAVCAN_STM32_TIMER_NUMBER, RST)
# else
#  error "This UAVCAN_STM32_TIMER_NUMBER is not supported yet"
# endif

# if (TIMX_INPUT_CLOCK % 1000000) != 0
#  error "No way, timer clock must be divisible to 1e6. FIXME!"
# endif

extern "C" UAVCAN_STM32_IRQ_HANDLER(TIMX_IRQHandler);

namespace uavcan_stm32
{
namespace clock
{
namespace
{

const uavcan::uint32_t USecPerOverflow = 65536;

Mutex mutex;

bool initialized = false;

bool utc_set = false;
bool utc_locked = false;
uavcan::uint32_t utc_jump_cnt = 0;
UtcSyncParams utc_sync_params;
float utc_prev_adj = 0;
float utc_rel_rate_ppm = 0;
float utc_rel_rate_error_integral = 0;
uavcan::int32_t utc_accumulated_correction_nsec = 0;
uavcan::int32_t utc_correction_nsec_per_overflow = 0;
uavcan::MonotonicTime prev_utc_adj_at;

uavcan::uint64_t time_mono = 0;
uavcan::uint64_t time_utc = 0;

}

#if UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS

static void nvicEnableVector(IRQn_Type irq,  uint8_t prio)
{
    #if !defined (USE_HAL_DRIVER)
      NVIC_InitTypeDef NVIC_InitStructure;
      NVIC_InitStructure.NVIC_IRQChannel = irq;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = prio;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
    #else
      HAL_NVIC_SetPriority(irq, prio, 0);
      HAL_NVIC_EnableIRQ(irq);
    #endif

}

#endif

void init()
{
    CriticalSectionLocker lock;
    if (initialized)
    {
        return;
    }
    initialized = true;


# if UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS
    // Power-on and reset
    TIMX_RCC_ENR |= TIMX_RCC_ENR_MASK;
    TIMX_RCC_RSTR |=  TIMX_RCC_RSTR_MASK;
    TIMX_RCC_RSTR &= ~TIMX_RCC_RSTR_MASK;

    // Enable IRQ
    nvicEnableVector(TIMX_IRQn,  UAVCAN_STM32_IRQ_PRIORITY_MASK);

# if (TIMX_INPUT_CLOCK % 1000000) != 0
#  error "No way, timer clock must be divisible to 1e6. FIXME!"
# endif

    // Start the timer
    TIMX->ARR  = 0xFFFF;
    TIMX->PSC  = (TIMX_INPUT_CLOCK / 1000000) - 1;  // 1 tick == 1 microsecond
    TIMX->CR1  = TIM_CR1_URS;
    TIMX->SR   = 0;
    TIMX->EGR  = TIM_EGR_UG;     // Reload immediately
    TIMX->DIER = TIM_DIER_UIE;
    TIMX->CR1  = TIM_CR1_CEN;    // Start

# endif

# if UAVCAN_STM32_NUTTX

    // Attach IRQ
    irq_attach(TIMX_IRQn, &TIMX_IRQHandler);

    // Power-on and reset
    modifyreg32(STM32_RCC_APB1ENR, 0, TIMX_RCC_ENR_MASK);
    modifyreg32(STM32_RCC_APB1RSTR, 0, TIMX_RCC_RSTR_MASK);
    modifyreg32(STM32_RCC_APB1RSTR, TIMX_RCC_RSTR_MASK, 0);


    // Start the timer
    putreg32(0xFFFF, TMR_REG(STM32_BTIM_ARR_OFFSET));
    putreg16(((TIMX_INPUT_CLOCK / 1000000)-1), TMR_REG(STM32_BTIM_PSC_OFFSET));
    putreg16(BTIM_CR1_URS, TMR_REG(STM32_BTIM_CR1_OFFSET));
    putreg16(0, TMR_REG(STM32_BTIM_SR_OFFSET));
    putreg16(BTIM_EGR_UG, TMR_REG(STM32_BTIM_EGR_OFFSET)); // Reload immediately
    putreg16(BTIM_DIER_UIE, TMR_REG(STM32_BTIM_DIER_OFFSET));<commit_msg>STM32: new config parameter UAVCAN_STM32_TIMX_INPUT_CLOCK<commit_after>/*
 * Copyright (C) 2014 <NAME> <<EMAIL>>
 */

#include <uavcan_stm32/clock.hpp>
#include <uavcan_stm32/thread.hpp>
#include "internal.hpp"

#if UAVCAN_STM32_TIMER_NUMBER

#include <cassert>
#include <cmath>

/*
 * Timer instance
 */
# if (UAVCAN_STM32_CHIBIOS && CH_KERNEL_MAJOR == 2) || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS
#  define TIMX                    UAVCAN_STM32_GLUE2(TIM, UAVCAN_STM32_TIMER_NUMBER)
#  define TIMX_IRQn               UAVCAN_STM32_GLUE3(TIM, UAVCAN_STM32_TIMER_NUMBER, _IRQn)
#  define TIMX_INPUT_CLOCK        STM32_TIMCLK1
# endif

# if (UAVCAN_STM32_CHIBIOS && (CH_KERNEL_MAJOR == 3 || CH_KERNEL_MAJOR == 4 || CH_KERNEL_MAJOR == 5))
#  define TIMX                    UAVCAN_STM32_GLUE2(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER)
#  define TIMX_IRQn               UAVCAN_STM32_GLUE3(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER, _NUMBER)
#  define TIMX_IRQHandler         UAVCAN_STM32_GLUE3(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER, _HANDLER)
#  define TIMX_INPUT_CLOCK        STM32_TIMCLK1
# else
#  define TIMX_IRQHandler         UAVCAN_STM32_GLUE3(TIM, UAVCAN_STM32_TIMER_NUMBER, _IRQHandler)
# endif

# if UAVCAN_STM32_NUTTX
#  define TIMX                    UAVCAN_STM32_GLUE3(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER, _BASE)
#  define  TMR_REG(o)              (TIMX + (o))
#  define TIMX_INPUT_CLOCK         UAVCAN_STM32_GLUE3(STM32_APB1_TIM, UAVCAN_STM32_TIMER_NUMBER, _CLKIN)

#  define TIMX_IRQn                UAVCAN_STM32_GLUE2(STM32_IRQ_TIM, UAVCAN_STM32_TIMER_NUMBER)
# endif

# if UAVCAN_STM32_TIMER_NUMBER >= 2 && UAVCAN_STM32_TIMER_NUMBER <= 7
#  define TIMX_RCC_ENR           RCC->APB1ENR
#  define TIMX_RCC_RSTR          RCC->APB1RSTR
#  define TIMX_RCC_ENR_MASK      UAVCAN_STM32_GLUE3(RCC_APB1ENR_TIM,  UAVCAN_STM32_TIMER_NUMBER, EN)
#  define TIMX_RCC_RSTR_MASK     UAVCAN_STM32_GLUE3(RCC_APB1RSTR_TIM, UAVCAN_STM32_TIMER_NUMBER, RST)
# else
#  error "This UAVCAN_STM32_TIMER_NUMBER is not supported yet"
# endif

/**
 * UAVCAN_STM32_TIMX_INPUT_CLOCK can be used to manually override the auto-detected timer clock speed.
 * This is useful at least with certain versions of ChibiOS which do not support the bit
 * RCC_DKCFGR.TIMPRE that is available in newer models of STM32. In that case, if TIMPRE is active,
 * the auto-detected value of TIMX_INPUT_CLOCK will be twice lower than the actual clock speed.
 * Read this for additional context: http://www.chibios.com/forum/viewtopic.php?f=35&t=3870
 * A normal way to use the override feature is to provide an alternative macro, e.g.:
 *
 *      -DUAVCAN_STM32_TIMX_INPUT_CLOCK=STM32_HCLK
 *
 * Alternatively, the new clock rate can be specified directly.
 */
# ifdef UAVCAN_STM32_TIMX_INPUT_CLOCK
#  undef TIMX_INPUT_CLOCK
#  define TIMX_INPUT_CLOCK      UAVCAN_STM32_TIMX_INPUT_CLOCK
# endif

extern "C" UAVCAN_STM32_IRQ_HANDLER(TIMX_IRQHandler);

namespace uavcan_stm32
{
namespace clock
{
namespace
{

const uavcan::uint32_t USecPerOverflow = 65536;

Mutex mutex;

bool initialized = false;

bool utc_set = false;
bool utc_locked = false;
uavcan::uint32_t utc_jump_cnt = 0;
UtcSyncParams utc_sync_params;
float utc_prev_adj = 0;
float utc_rel_rate_ppm = 0;
float utc_rel_rate_error_integral = 0;
uavcan::int32_t utc_accumulated_correction_nsec = 0;
uavcan::int32_t utc_correction_nsec_per_overflow = 0;
uavcan::MonotonicTime prev_utc_adj_at;

uavcan::uint64_t time_mono = 0;
uavcan::uint64_t time_utc = 0;

}

#if UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS

static void nvicEnableVector(IRQn_Type irq,  uint8_t prio)
{
    #if !defined (USE_HAL_DRIVER)
      NVIC_InitTypeDef NVIC_InitStructure;
      NVIC_InitStructure.NVIC_IRQChannel = irq;
      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = prio;
      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      NVIC_Init(&NVIC_InitStructure);
    #else
      HAL_NVIC_SetPriority(irq, prio, 0);
      HAL_NVIC_EnableIRQ(irq);
    #endif

}

#endif

void init()
{
    CriticalSectionLocker lock;
    if (initialized)
    {
        return;
    }
    initialized = true;


# if UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS
    // Power-on and reset
    TIMX_RCC_ENR |= TIMX_RCC_ENR_MASK;
    TIMX_RCC_RSTR |=  TIMX_RCC_RSTR_MASK;
    TIMX_RCC_RSTR &= ~TIMX_RCC_RSTR_MASK;

    // Enable IRQ
    nvicEnableVector(TIMX_IRQn,  UAVCAN_STM32_IRQ_PRIORITY_MASK);

# if (TIMX_INPUT_CLOCK % 1000000) != 0
#  error "No way, timer clock must be divisible by 1e6. FIXME!"
# endif

    // Start the timer
    TIMX->ARR  = 0xFFFF;
    TIMX->PSC  = (TIMX_INPUT_CLOCK / 1000000) - 1;  // 1 tick == 1 microsecond
    TIMX->CR1  = TIM_CR1_URS;
    TIMX->SR   = 0;
    TIMX->EGR  = TIM_EGR_UG;     // Reload immediately
    TIMX->DIER = TIM_DIER_UIE;
    TIMX->CR1  = TIM_CR1_CEN;    // Start

# endif

# if UAVCAN_STM32_NUTTX

    // Attach IRQ
    irq_attach(TIMX_IRQn, &TIMX_IRQHandler);

    // Power-on and reset
    modifyreg32(STM32_RCC_APB1ENR, 0, TIMX_RCC_ENR_MASK);
    modifyreg32(STM32_RCC_APB1RSTR, 0, TIMX_RCC_RSTR_MASK);
    modifyreg32(STM32_RCC_APB1RSTR, TIMX_RCC_RSTR_MASK, 0);


    // Start the timer
    putreg32(0xFFFF, TMR_REG(STM32_BTIM_ARR_OFFSET));
    putreg16(((TIMX_INPUT_CLOCK / 1000000)-1), TMR_REG(STM32_BTIM_PSC_OFFSET));
    putreg16(BTIM_CR1_URS, TMR_REG(STM32_BTIM_CR1_OFFSET));
    putreg16(0, TMR_REG(STM32_BTIM_SR_OFFSET));
    putreg16(BTIM_EGR_UG, TMR_REG(STM32_BTIM_EGR_OFFSET)); // Reload immediately
    putreg16(BTIM_DIER_UIE, TMR_REG(STM32_BTIM_DIER_OFFSET));
{'fraction_non_alphanumeric': 0.08418024928092042, 'fraction_numerical': 0.04832214765100671, 'mean_word_length': 4.1921353907416625, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5624125', 'n_tokens_mistral': 4774, 'n_tokens_neox': 4293, 'n_words': 732}