rt-thread-official/bsp/nuvoton/libraries/n9h30/rtt_port/drv_etimer.c

284 lines
7.0 KiB
C

/**************************************************************************//**
*
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2020-12-3 Wayne First version
*
******************************************************************************/
#include <rtconfig.h>
#if defined(BSP_USING_ETIMER) && defined(RT_USING_HWTIMER)
#include <rtdevice.h>
#include "NuMicro.h"
#include <drv_sys.h>
/* Private define ---------------------------------------------------------------*/
#define NU_TIMER_DEVICE(etimer) (nu_etimer_t)(etimer)
enum
{
ETIMER_START = -1,
#if defined(BSP_USING_ETIMER0)
ETIMER0_IDX,
#endif
#if defined(BSP_USING_ETIMER1)
ETIMER1_IDX,
#endif
#if defined(BSP_USING_ETIMER2)
ETIMER2_IDX,
#endif
#if defined(BSP_USING_ETIMER3)
ETIMER3_IDX,
#endif
ETIMER_CNT
};
/* Private typedef --------------------------------------------------------------*/
struct nu_etimer
{
rt_hwtimer_t parent;
char *name;
uint32_t idx;
IRQn_Type irqn;
E_SYS_IPRST rstidx;
E_SYS_IPCLK clkidx;
};
typedef struct nu_etimer *nu_etimer_t;
/* Private functions ------------------------------------------------------------*/
static void nu_etimer_init(rt_hwtimer_t *timer, rt_uint32_t state);
static rt_err_t nu_etimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t opmode);
static void nu_etimer_stop(rt_hwtimer_t *timer);
static rt_uint32_t nu_etimer_count_get(rt_hwtimer_t *timer);
static rt_err_t nu_etimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args);
/* Public functions -------------------------------------------------------------*/
/* Private variables ------------------------------------------------------------*/
static struct nu_etimer nu_etimer_arr [] =
{
#if defined(BSP_USING_ETIMER0)
{
.name = "etmr0",
.idx = 0,
.irqn = IRQ_ETMR0,
.rstidx = ETIMER0RST,
.clkidx = ETIMER0CKEN,
},
#endif
#if defined(BSP_USING_ETIMER1)
{
.name = "etmr1",
.idx = 1,
.irqn = IRQ_ETMR1,
.rstidx = ETIMER1RST,
.clkidx = ETIMER1CKEN,
},
#endif
#if defined(BSP_USING_ETIMER2)
{
.name = "etmr2",
.idx = 2,
.irqn = IRQ_ETMR2,
.rstidx = ETIMER2RST,
.clkidx = ETIMER2CKEN,
},
#endif
#if defined(BSP_USING_ETIMER3)
{
.name = "etmr3",
.idx = 3,
.irqn = IRQ_ETMR3,
.rstidx = ETIMER3RST,
.clkidx = ETIMER3CKEN,
},
#endif
};
static struct rt_hwtimer_info nu_etimer_info =
{
12000000, /* maximum count frequency */
46875, /* minimum count frequency */
0xFFFFFF, /* the maximum counter value */
HWTIMER_CNTMODE_UP, /* Increment or Decreasing count mode */
};
static struct rt_hwtimer_ops nu_etimer_ops =
{
nu_etimer_init,
nu_etimer_start,
nu_etimer_stop,
nu_etimer_count_get,
nu_etimer_control
};
/* Functions define ------------------------------------------------------------*/
static void nu_etimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
{
nu_etimer_t psNuETmr = NU_TIMER_DEVICE(timer);
RT_ASSERT(psNuETmr != RT_NULL);
if (1 == state)
{
uint32_t timer_clk;
struct rt_hwtimer_info *info = &nu_etimer_info;
timer_clk = ETIMER_GetModuleClock(psNuETmr->idx);
info->maxfreq = timer_clk;
info->minfreq = timer_clk / 256;
ETIMER_Open(psNuETmr->idx, ETIMER_ONESHOT_MODE, 1);
ETIMER_EnableInt(psNuETmr->idx);
rt_hw_interrupt_umask(psNuETmr->irqn);
}
else
{
rt_hw_interrupt_mask(psNuETmr->irqn);
ETIMER_DisableInt(psNuETmr->idx);
ETIMER_Close(psNuETmr->idx);
}
}
static rt_err_t nu_etimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t opmode)
{
rt_err_t ret = RT_EINVAL;
rt_uint32_t u32OpMode;
nu_etimer_t psNuETmr = NU_TIMER_DEVICE(timer);
RT_ASSERT(psNuETmr != RT_NULL);
if (cnt <= 1 || cnt > 0xFFFFFF)
{
goto exit_nu_etimer_start;
}
switch (opmode)
{
case HWTIMER_MODE_PERIOD:
u32OpMode = ETIMER_PERIODIC_MODE;
break;
case HWTIMER_MODE_ONESHOT:
u32OpMode = ETIMER_ONESHOT_MODE;
break;
default:
goto exit_nu_etimer_start;
}
ETIMER_SET_CMP_VALUE(psNuETmr->idx, cnt);
ETIMER_SET_OPMODE(psNuETmr->idx, u32OpMode);
ETIMER_EnableInt(psNuETmr->idx);
rt_hw_interrupt_umask(psNuETmr->irqn);
ETIMER_Start(psNuETmr->idx);
ret = RT_EOK;
exit_nu_etimer_start:
return -(ret);
}
static void nu_etimer_stop(rt_hwtimer_t *timer)
{
nu_etimer_t psNuETmr = NU_TIMER_DEVICE(timer);
RT_ASSERT(psNuETmr != RT_NULL);
rt_hw_interrupt_mask(psNuETmr->irqn);
ETIMER_DisableInt(psNuETmr->idx);
ETIMER_Stop(psNuETmr->idx);
ETIMER_ClearCounter(psNuETmr->idx);
}
static rt_uint32_t nu_etimer_count_get(rt_hwtimer_t *timer)
{
nu_etimer_t psNuETmr = NU_TIMER_DEVICE(timer);
RT_ASSERT(psNuETmr != RT_NULL);
return ETIMER_GetCounter(psNuETmr->idx);
}
static rt_err_t nu_etimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
{
rt_err_t ret = RT_EOK;
nu_etimer_t psNuETmr = NU_TIMER_DEVICE(timer);
RT_ASSERT(psNuETmr != RT_NULL);
switch (cmd)
{
case HWTIMER_CTRL_FREQ_SET:
{
uint32_t clk;
uint32_t pre;
clk = ETIMER_GetModuleClock(psNuETmr->idx);
pre = clk / *((uint32_t *)args) - 1;
ETIMER_SET_PRESCALE_VALUE(psNuETmr->idx, pre);
*((uint32_t *)args) = clk / (pre + 1) ;
}
break;
case HWTIMER_CTRL_STOP:
ETIMER_Stop(psNuETmr->idx);
break;
default:
ret = RT_EINVAL;
break;
}
return -(ret);
}
/**
* All UART interrupt service routine
*/
static void nu_etimer_isr(int vector, void *param)
{
nu_etimer_t psNuETmr = NU_TIMER_DEVICE(param);
RT_ASSERT(psNuETmr != RT_NULL);
if (ETIMER_GetIntFlag(psNuETmr->idx))
{
ETIMER_ClearIntFlag(psNuETmr->idx);
rt_device_hwtimer_isr(&psNuETmr->parent);
}
}
int rt_hw_etimer_init(void)
{
int i;
rt_err_t ret = RT_EOK;
for (i = (ETIMER_START + 1); i < ETIMER_CNT; i++)
{
nu_sys_ipclk_enable(nu_etimer_arr[i].clkidx);
nu_sys_ip_reset(nu_etimer_arr[i].rstidx);
/* Register Etimer information. */
nu_etimer_arr[i].parent.info = &nu_etimer_info;
/* Register Etimer operation. */
nu_etimer_arr[i].parent.ops = &nu_etimer_ops;
/* Register Etimer interrupt service routine. */
rt_hw_interrupt_install(nu_etimer_arr[i].irqn, nu_etimer_isr, &nu_etimer_arr[i], nu_etimer_arr[i].name);
/* Register RT hwtimer device. */
ret = rt_device_hwtimer_register(&nu_etimer_arr[i].parent, nu_etimer_arr[i].name, &nu_etimer_arr[i]);
RT_ASSERT(ret == RT_EOK);
}
return 0;
}
INIT_BOARD_EXPORT(rt_hw_etimer_init);
#endif //#if defined(BSP_USING_ETIMER) && defined(RT_USING_HWTIMER)