rt-thread/bsp/n32/libraries/n32_drivers/drv_hwtimer.c

584 lines
15 KiB
C

/*****************************************************************************
* Copyright (c) 2019, Nations Technologies Inc.
*
* All rights reserved.
* ****************************************************************************
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the disclaimer below.
*
* Nations' name may not be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* DISCLAIMED. IN NO EVENT SHALL NATIONS 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.
* ****************************************************************************/
/**
* @file drv_hwtimer.c
* @author Nations
* @version v1.0.0
*
* @copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved.
*/
#include "drv_hwtimer.h"
#ifdef RT_USING_HWTIMER
#if defined(BSP_USING_HWTIMER1) || defined(BSP_USING_HWTIMER2) || defined(BSP_USING_HWTIMER3) \
|| defined(BSP_USING_HWTIMER4) || defined(BSP_USING_HWTIMER5) || defined(BSP_USING_HWTIMER6) \
|| defined(BSP_USING_HWTIMER7) || defined(BSP_USING_HWTIMER8)
/* this driver can be disabled at menuconfig -> Hardware Drivers Config -> On-chip Peripheral Drivers -> Enable HWTIMER */
static struct n32_hwtimer_config hwtimer_config[] =
{
#ifdef BSP_USING_HWTIMER1
{
"timer1",
TIM1,
TIM1_UP_IRQn,
},
#endif
#ifdef BSP_USING_HWTIMER2
{
"timer2",
TIM2,
TIM2_IRQn,
},
#endif
#ifdef BSP_USING_HWTIMER3
{
"timer3",
TIM3,
TIM3_IRQn,
},
#endif
#ifdef BSP_USING_HWTIMER4
{
"timer4",
TIM4,
TIM4_IRQn,
},
#endif
#ifdef BSP_USING_HWTIMER5
{
"timer5",
TIM5,
TIM5_IRQn,
},
#endif
#ifdef BSP_USING_HWTIMER6
{
"timer6",
TIM6,
TIM6_IRQn,
},
#endif
#ifdef BSP_USING_HWTIMER7
{
"timer7",
TIM7,
TIM7_IRQn,
},
#endif
#ifdef BSP_USING_HWTIMER8
{
"timer8",
TIM8,
TIM8_UP_IRQn,
},
#endif
};
uint8_t tim1_count = 0, tim2_count = 0, tim3_count = 0, tim4_count = 0,tim5_count = 0, tim6_count = 0, tim7_count = 0, tim8_count = 0;
static void caculate_tim_count()
{
uint8_t count = 0;
#ifdef BSP_USING_HWTIMER1
tim1_count = count;
count++;
#endif
#ifdef BSP_USING_HWTIMER2
tim2_count = count;
count++;
#endif
#ifdef BSP_USING_HWTIMER3
tim3_count = count;
count++;
#endif
#ifdef BSP_USING_HWTIMER4
tim4_count = count;
count++;
#endif
#ifdef BSP_USING_HWTIMER5
tim5_count = count;
count++;
#endif
#ifdef BSP_USING_HWTIMER6
tim6_count = count;
count++;
#endif
#ifdef BSP_USING_HWTIMER7
tim7_count = count;
count++;
#endif
#ifdef BSP_USING_HWTIMER8
tim8_count = count;
count++;
#endif
}
#define BITS(start, end) ((0xFFFFFFFFUL << (start)) & (0xFFFFFFFFUL >> (31U - (uint32_t)(end))))
#define GET_BITS(regval, start, end) (((regval) & BITS((start),(end))) >> (start))
static struct n32_hwtimer hwtimer_obj[sizeof(hwtimer_config) / sizeof(hwtimer_config[0])] = {0};
static rt_err_t n32_hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
{
rt_err_t err = RT_EOK;
struct n32_hwtimer_config *config;
RCC_ClocksType RCC_ClockFreq;
RT_ASSERT(timer != RT_NULL);
config = (struct n32_hwtimer_config *)timer->parent.user_data;
RCC_GetClocksFreqValue(&RCC_ClockFreq);
switch (cmd)
{
case HWTIMER_CTRL_FREQ_SET:
{
uint32_t clk;
uint8_t clkpre;
uint32_t pre;
if (config->timer_periph != TIM1 && config->timer_periph != TIM8)
{
clk = RCC_ClockFreq.Pclk1Freq;
clkpre = GET_BITS(RCC->CFG, 8, 10);
}
else
{
clk = RCC_ClockFreq.Pclk2Freq;
clkpre = GET_BITS(RCC->CFG, 11, 13);
}
if (clkpre >= 4)
{
clk = clk * 2;
}
pre = (clk / * ((uint32_t *)args)) - 1;
TIM_ConfigPrescaler(config->timer_periph, pre, TIM_PSC_RELOAD_MODE_IMMEDIATE);
config->timer_periph->EVTGEN |= TIM_EVTGEN_UDGN;
}
break;
case HWTIMER_CTRL_STOP:
TIM_Enable(config->timer_periph, DISABLE);
break;
default:
err = -RT_ENOSYS;
break;
}
return err;
}
static rt_uint32_t n32_hwtimer_count_get(rt_hwtimer_t *timer)
{
rt_uint32_t CurrentTimer_Count;
struct n32_hwtimer_config *config;
RT_ASSERT(timer != RT_NULL);
config = (struct n32_hwtimer_config *)timer->parent.user_data;
CurrentTimer_Count = TIM_GetCnt(config->timer_periph);
return CurrentTimer_Count;
}
/**
* @brief Configures the NVIC for TIM.
*/
void TIM_NVIC_Config(IRQn_Type IRQn, uint8_t PreemptionPriority, uint8_t SubPriority,FunctionalState cmd)
{
NVIC_InitType NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = cmd;
if(cmd)
{
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = SubPriority;
}
NVIC_Init(&NVIC_InitStructure);
}
static void n32_hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
{
struct n32_hwtimer_config *config;
TIM_TimeBaseInitType TIM_TimeBaseStructure;
RCC_ClocksType RCC_ClockFreq;
RT_ASSERT(timer != RT_NULL);
config = (struct n32_hwtimer_config *)timer->parent.user_data;
if (state == 1)
{
uint32_t clk;
uint8_t clkpre;
uint32_t pre;
RCC_GetClocksFreqValue(&RCC_ClockFreq);
TIM_DeInit(config->timer_periph);
if (config->timer_periph != TIM1 && config->timer_periph != TIM8)
{
clk = RCC_ClockFreq.Pclk1Freq;
clkpre = GET_BITS(RCC->CFG, 8, 10);
}
else
{
clk = RCC_ClockFreq.Pclk2Freq;
clkpre = GET_BITS(RCC->CFG, 11, 13);
}
if (clkpre >= 4)
{
clk = clk * 2;
}
pre = (clk / 10000) - 1;
/* Time Base configuration */
TIM_TimeBaseStructure.Prescaler = pre;
TIM_TimeBaseStructure.CntMode = TIM_CNT_MODE_UP;
TIM_TimeBaseStructure.Period = 10000 - 1;
TIM_TimeBaseStructure.ClkDiv = TIM_CLK_DIV1;
TIM_TimeBaseStructure.RepetCnt = 0;
if (timer->info->cntmode == HWTIMER_CNTMODE_UP)
{
TIM_TimeBaseStructure.CntMode = TIM_CNT_MODE_UP;
}
else
{
TIM_TimeBaseStructure.CntMode = TIM_CNT_MODE_DOWN;
}
TIM_InitTimeBase(config->timer_periph, &TIM_TimeBaseStructure);
/* set the TIMx priority */
TIM_NVIC_Config(config->irqn, 3, 0, ENABLE);
/* clear update flag */
TIM_ClearFlag(config->timer_periph, TIM_FLAG_UPDATE);
}
else
{
TIM_Enable(config->timer_periph, DISABLE);
TIM_ConfigInt(config->timer_periph, TIM_INT_UPDATE, ENABLE);
TIM_NVIC_Config(config->irqn, 3, 0, DISABLE);
}
}
static rt_err_t n32_hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
{
struct n32_hwtimer_config *config;
RT_ASSERT(timer != RT_NULL);
config = (struct n32_hwtimer_config *)timer->parent.user_data;
/* set tim cnt */
TIM_SetCnt(config->timer_periph, 0);
/* set tim arr */
TIM_SetAutoReload(config->timer_periph, cnt - 1);
if (mode == HWTIMER_MODE_ONESHOT)
{
TIM_SelectOnePulseMode(config->timer_periph, TIM_OPMODE_SINGLE);
}
else
{
TIM_SelectOnePulseMode(config->timer_periph, TIM_OPMODE_REPET);
}
/* start timer */
TIM_ConfigInt(config->timer_periph, TIM_INT_UPDATE, ENABLE);
/* TIM counter enable */
TIM_Enable(config->timer_periph, ENABLE);
TIM_NVIC_Config(config->irqn, 3, 0, ENABLE);
return RT_EOK;
}
static void n32_hwtimer_stop(rt_hwtimer_t *timer)
{
struct n32_hwtimer_config *config;
RT_ASSERT(timer != RT_NULL);
config = (struct n32_hwtimer_config *)timer->parent.user_data;
TIM_Enable(config->timer_periph, DISABLE);
TIM_NVIC_Config(config->irqn, 3, 0, DISABLE);
}
static const struct rt_hwtimer_ops n32_hwtimer_ops =
{
.init = n32_hwtimer_init,
.start = n32_hwtimer_start,
.stop = n32_hwtimer_stop,
.count_get = n32_hwtimer_count_get,
.control = n32_hwtimer_control,
};
static const struct rt_hwtimer_info n32_hwtimer_info =
{
1000000, /* the maximum count frequency can be set */
2000, /* the minimum count frequency can be set */
0xFFFF,
HWTIMER_CNTMODE_UP,
};
/**
* @brief This function handles TIM interrupts requests.
* @param htim TIM handle
* @retval None
*/
void TIM_IRQHandler(TIM_Module* timer_periph)
{
/* Capture compare 1 event */
if(TIM_GetFlagStatus(timer_periph, TIM_FLAG_CC1) != RESET)
{
if(TIM_GetIntStatus(timer_periph, TIM_INT_CC1) !=RESET)
{
{
TIM_ClrIntPendingBit(timer_periph, TIM_INT_CC1);
}
}
}
/* Capture compare 2 event */
if(TIM_GetFlagStatus(timer_periph, TIM_FLAG_CC2) != RESET)
{
if(TIM_GetIntStatus(timer_periph, TIM_INT_CC2) !=RESET)
{
TIM_ClrIntPendingBit(timer_periph, TIM_INT_CC2);
}
}
/* Capture compare 3 event */
if(TIM_GetFlagStatus(timer_periph, TIM_FLAG_CC3) != RESET)
{
if(TIM_GetIntStatus(timer_periph, TIM_INT_CC3) !=RESET)
{
TIM_ClrIntPendingBit(timer_periph, TIM_INT_CC3);
}
}
/* Capture compare 4 event */
if(TIM_GetFlagStatus(timer_periph, TIM_FLAG_CC4) != RESET)
{
if(TIM_GetIntStatus(timer_periph, TIM_INT_CC4) !=RESET)
{
TIM_ClrIntPendingBit(timer_periph, TIM_INT_CC4);
}
}
/* TIM Update event */
if(TIM_GetFlagStatus(timer_periph, TIM_FLAG_UPDATE) != RESET)
{
if(TIM_GetIntStatus(timer_periph, TIM_INT_UPDATE) !=RESET)
{
TIM_ClrIntPendingBit(timer_periph, TIM_INT_UPDATE);
}
}
/* TIM Break input event */
if(TIM_GetFlagStatus(timer_periph, TIM_FLAG_BREAK) != RESET)
{
if(TIM_GetIntStatus(timer_periph, TIM_INT_BREAK) !=RESET)
{
TIM_ClrIntPendingBit(timer_periph, TIM_INT_BREAK);
}
}
/* TIM Trigger detection event */
if(TIM_GetFlagStatus(timer_periph, TIM_FLAG_TRIG) != RESET)
{
if(TIM_GetIntStatus(timer_periph, TIM_INT_TRIG) !=RESET)
{
TIM_ClrIntPendingBit(timer_periph, TIM_INT_TRIG);
}
}
/* TIM commutation event */
if(TIM_GetFlagStatus(timer_periph, TIM_FLAG_COM) != RESET)
{
if(TIM_GetIntStatus(timer_periph, TIM_INT_COM) !=RESET)
{
TIM_ClrIntPendingBit(timer_periph, TIM_INT_COM);
}
}
}
#ifdef BSP_USING_HWTIMER1
void TIM1_UP_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
// TIM_IRQHandler(hwtimer_obj[0].config->timer_periph);
TIM_ClrIntPendingBit(hwtimer_obj[tim1_count].config->timer_periph, TIM_INT_UPDATE);
rt_device_hwtimer_isr(&hwtimer_obj[tim1_count].time_device);
/* leave interrupt */
rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_HWTIMER2
void TIM2_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
TIM_ClrIntPendingBit(hwtimer_obj[tim2_count].config->timer_periph, TIM_INT_UPDATE);
rt_device_hwtimer_isr(&hwtimer_obj[tim2_count].time_device);
/* leave interrupt */
rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_HWTIMER3
void TIM3_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
TIM_ClrIntPendingBit(hwtimer_obj[tim3_count].config->timer_periph, TIM_INT_UPDATE);
rt_device_hwtimer_isr(&hwtimer_obj[tim3_count].time_device);
/* leave interrupt */
rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_HWTIMER4
void TIM4_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
TIM_ClrIntPendingBit(hwtimer_obj[tim4_count].config->timer_periph, TIM_INT_UPDATE);
rt_device_hwtimer_isr(&hwtimer_obj[tim4_count].time_device);
/* leave interrupt */
rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_HWTIMER5
void TIM5_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
TIM_ClrIntPendingBit(hwtimer_obj[tim5_count].config->timer_periph, TIM_INT_UPDATE);
rt_device_hwtimer_isr(&hwtimer_obj[tim5_count].time_device);
/* leave interrupt */
rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_HWTIMER6
void TIM6_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
TIM_ClrIntPendingBit(hwtimer_obj[tim6_count].config->timer_periph, TIM_INT_UPDATE);
rt_device_hwtimer_isr(&hwtimer_obj[tim6_count].time_device);
/* leave interrupt */
rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_HWTIMER7
void TIM7_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
TIM_ClrIntPendingBit(hwtimer_obj[tim7_count].config->timer_periph, TIM_INT_UPDATE);
rt_device_hwtimer_isr(&hwtimer_obj[tim7_count].time_device);
/* leave interrupt */
rt_interrupt_leave();
}
#endif
#ifdef BSP_USING_HWTIMER8
void TIM8_UP_IRQHandler(void)
{
/* enter interrupt */
rt_interrupt_enter();
TIM_ClrIntPendingBit(hwtimer_obj[tim8_count].config->timer_periph, TIM_INT_UPDATE);
rt_device_hwtimer_isr(&hwtimer_obj[tim8_count].time_device);
/* leave interrupt */
rt_interrupt_leave();
}
#endif
int rt_hwtimer_init(void)
{
int i = 0;
int result = RT_EOK;
#ifdef BSP_USING_HWTIMER1
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_TIM1, ENABLE);
#endif
#ifdef BSP_USING_HWTIMER2
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM2, ENABLE);
#endif
#ifdef BSP_USING_HWTIMER3
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM3, ENABLE);
#endif
#ifdef BSP_USING_HWTIMER4
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM4, ENABLE);
#endif
#ifdef BSP_USING_HWTIMER5
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM5, ENABLE);
#endif
#ifdef BSP_USING_HWTIMER6
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM6, ENABLE);
#endif
#ifdef BSP_USING_HWTIMER7
RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM7, ENABLE);
#endif
#ifdef BSP_USING_HWTIMER8
RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_TIM8, ENABLE);
#endif
caculate_tim_count();
for (i = 0; i < sizeof(hwtimer_obj) / sizeof(hwtimer_obj[0]); i++)
{
hwtimer_obj[i].time_device.info = &n32_hwtimer_info;
hwtimer_obj[i].time_device.ops = &n32_hwtimer_ops;
hwtimer_obj[i].config = &hwtimer_config[i];
rt_device_hwtimer_register(&hwtimer_obj[i].time_device, \
hwtimer_obj[i].config->name, hwtimer_obj[i].config);
}
return result;
}
INIT_DEVICE_EXPORT(rt_hwtimer_init);
#endif /* defined(BSP_USING_HWTIMERx) */
#endif /* RT_USING_HWTIMER */