Sfoglia il codice sorgente

[bsp][nxp/mcxn] hwtimer: initial support for MRT.

This patch adds support for hwtimer using MRT0 instance which simulates
4 independent timers. The frequency is fixed to AHB bus frequency and
not adjustable.

Signed-off-by: Yilin Sun <imi415@imi.moe>
Yilin Sun 1 anno fa
parent
commit
c224278d3e

+ 183 - 0
bsp/nxp/mcxn/Libraries/drivers/drv_hwtimer.c

@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+* Change Logs:
+* Date           Author       Notes
+* 2024-02-21     Yilin Sun    Initial revision.
+*/
+
+#include "drv_hwtimer.h"
+
+#ifdef BSP_USING_HWTIMER
+
+#include "fsl_mrt.h"
+
+typedef struct
+{
+    rt_hwtimer_t timer_device;
+    mrt_chnl_t channel;
+    char *name;
+} mcx_hwtimer_obj_t;
+
+static inline rt_err_t mcx_hwtimer_mode_set(mcx_hwtimer_obj_t *handle, rt_hwtimer_mode_t mode)
+{
+    mrt_timer_mode_t mrt_mode;
+    switch (mode)
+    {
+    case HWTIMER_MODE_ONESHOT:
+        mrt_mode = kMRT_OneShotMode;
+        break;
+
+    case HWTIMER_MODE_PERIOD:
+        mrt_mode = kMRT_RepeatMode;
+        break;
+
+    default:
+        return -RT_EINVAL;
+    }
+
+    MRT_SetupChannelMode(MRT0, handle->channel, mrt_mode);
+
+    return RT_EOK;
+}
+
+static void mcx_hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
+{
+    mrt_config_t mrt_config;
+    MRT_GetDefaultConfig(&mrt_config);
+
+    MRT_Init(MRT0, &mrt_config);
+}
+
+static rt_err_t mcx_hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
+{
+    rt_err_t ret = RT_EOK;
+
+    mcx_hwtimer_obj_t *handle = timer->parent.user_data;
+
+    MRT_StopTimer(MRT0, handle->channel);
+
+    ret = mcx_hwtimer_mode_set(handle, mode);
+    if (ret != RT_EOK)
+    {
+        return ret;
+    }
+
+    MRT_StartTimer(MRT0, handle->channel, cnt);
+    MRT_EnableInterrupts(MRT0, handle->channel, kMRT_TimerInterruptEnable);
+
+    return ret;
+}
+
+static void mcx_hwtimer_stop(rt_hwtimer_t *timer)
+{
+    mcx_hwtimer_obj_t *handle = timer->parent.user_data;
+    MRT_StopTimer(MRT0, handle->channel);
+    MRT_DisableInterrupts(MRT0, handle->channel, kMRT_TimerInterruptEnable);
+}
+
+static rt_uint32_t mcx_hwtimer_count_get(rt_hwtimer_t *timer)
+{
+    mcx_hwtimer_obj_t *handle = timer->parent.user_data;
+
+    return MRT_GetCurrentTimerCount(MRT0, handle->channel);
+}
+
+static rt_err_t mcx_hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
+{
+    rt_err_t ret = RT_EOK;
+
+    mcx_hwtimer_obj_t *handle = timer->parent.user_data;
+    switch (cmd)
+    {
+    case HWTIMER_CTRL_STOP:
+        mcx_hwtimer_stop(timer);
+        break;
+
+    case HWTIMER_CTRL_MODE_SET:
+        ret = mcx_hwtimer_mode_set(handle, *(rt_hwtimer_mode_t *)args);
+        if (ret != RT_EOK)
+        {
+            return ret;
+        }
+        break;
+
+    default:
+        return -RT_EINVAL;
+    }
+
+    return RT_EOK;
+}
+
+static mcx_hwtimer_obj_t mcx_hwtimer_list[] =
+{
+    { .name = "timer0", .channel = kMRT_Channel_0, },
+    { .name = "timer1", .channel = kMRT_Channel_1, },
+    { .name = "timer2", .channel = kMRT_Channel_2, },
+    { .name = "timer3", .channel = kMRT_Channel_3, },
+};
+
+static struct rt_hwtimer_info mcx_hwtimer_info =
+{
+    .cntmode = HWTIMER_CNTMODE_DW,
+    .maxcnt = 0x00FFFFFF, /* 24bit counter */
+    .minfreq = 150000000,
+    .maxfreq = 150000000,
+};
+
+static const struct rt_hwtimer_ops mcx_hwtimer_ops =
+{
+    .init = mcx_hwtimer_init,
+    .control = mcx_hwtimer_control,
+    .start = mcx_hwtimer_start,
+    .stop = mcx_hwtimer_stop,
+    .count_get = mcx_hwtimer_count_get,
+};
+
+int rt_hw_hwtimer_init(void)
+{
+    /* MRT frequency is fixed to AHB clock */
+    uint32_t mrt_freq = CLOCK_GetFreq(kCLOCK_BusClk);
+
+    mcx_hwtimer_info.minfreq = mrt_freq;
+    mcx_hwtimer_info.maxfreq = mrt_freq;
+
+    for (uint8_t i = 0; i < ARRAY_SIZE(mcx_hwtimer_list); i++)
+    {
+        mcx_hwtimer_list[i].timer_device.info = &mcx_hwtimer_info;
+        mcx_hwtimer_list[i].timer_device.ops = &mcx_hwtimer_ops;
+
+        rt_err_t ret = rt_device_hwtimer_register(&mcx_hwtimer_list[i].timer_device, mcx_hwtimer_list[i].name, &mcx_hwtimer_list[i]);
+        if (ret != RT_EOK)
+        {
+            return ret;
+        }
+    }
+
+    EnableIRQ(MRT0_IRQn);
+
+    return RT_EOK;
+}
+
+void MRT0_IRQHandler(void)
+{
+    /* Get channel interrupt flags */
+    uint32_t mrt_flag = MRT0->IRQ_FLAG;
+
+    /* Clear interrupt flags (W1C). */
+    MRT0->IRQ_FLAG = mrt_flag;
+
+    for (uint8_t i = 0; i < 4; i++)
+    {
+        if (mrt_flag & (1U << i))
+        {
+            rt_device_hwtimer_isr(&mcx_hwtimer_list[i].timer_device);
+        }
+    }
+}
+
+INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
+
+#endif /* BSP_USING_HWTIMER */

+ 20 - 0
bsp/nxp/mcxn/Libraries/drivers/drv_hwtimer.h

@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2006-2024, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+* Change Logs:
+* Date           Author       Notes
+* 2024-02-21     Yilin Sun    Initial revision.
+*/
+
+#ifndef __DRV_HWTIMER_H__
+#define __DRV_HWTIMER_H__
+
+#include <rtthread.h>
+#include <rtdevice.h>
+
+int rt_hw_hwtimer_init(void);
+
+#endif /* __DRV_HWTIMER_H__ */
+