drv_hwtimer.c 6.6 KB
Newer Older
G
greedyhao 已提交
1 2
/*
 * Copyright (c) 2020-2021, Bluetrum Development Team
mysterywolf's avatar
mysterywolf 已提交
3
 *
G
greedyhao 已提交
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author            Notes
 * 2021-01-22     greedyhao         first version
 */

#include "board.h"
#ifdef BSP_USING_TIM
#include "tim_config.h"

//#define DRV_DEBUG
#define LOG_TAG             "drv.hwtimer"
#include <drv_log.h>

#ifdef RT_USING_HWTIMER

enum
{
#ifdef BSP_USING_TIM1
    TIM1_INDEX,
#endif
#ifdef BSP_USING_TIM2
    TIM2_INDEX,
#endif
#ifdef BSP_USING_TIM3
    TIM3_INDEX,
#endif
#ifdef BSP_USING_TIM4
    TIM4_INDEX,
#endif
#ifdef BSP_USING_TIM5
    TIM5_INDEX,
#endif
};

struct ab32_hwtimer
{
    rt_hwtimer_t time_device;
    hal_sfr_t     tim_handle;
    char *name;
    irq_type tim_irqn;
};

static struct ab32_hwtimer ab32_hwtimer_obj[] =
{
#ifdef BSP_USING_TIM1
    TIM1_CONFIG,
#endif

#ifdef BSP_USING_TIM2
    TIM2_CONFIG,
#endif

#ifdef BSP_USING_TIM3
    TIM3_CONFIG,
#endif

#ifdef BSP_USING_TIM4
    TIM4_CONFIG,
#endif

#ifdef BSP_USING_TIM5
    TIM5_CONFIG,
#endif
};

G
greedyhao 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
RT_SECTION(".irq.timer")
static void _rt_device_hwtimer_isr(rt_hwtimer_t *timer)
{
    RT_ASSERT(timer != RT_NULL);

    timer->overflow ++;

    if (timer->cycles != 0)
    {
        timer->cycles --;
    }

    if (timer->cycles == 0)
    {
        timer->cycles = timer->reload;

        if (timer->mode == HWTIMER_MODE_ONESHOT)
        {
            if (timer->ops->stop != RT_NULL)
            {
                timer->ops->stop(timer);
            }
        }

        if (timer->parent.rx_indicate != RT_NULL)
        {
            timer->parent.rx_indicate(&timer->parent, sizeof(struct rt_hwtimerval));
        }
    }
}

G
greedyhao 已提交
102 103
static void timer_init(struct rt_hwtimer_device *timer, rt_uint32_t state)
{
104
    rt_uint32_t prescaler_value = 0;
G
greedyhao 已提交
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
    hal_sfr_t tim = RT_NULL;
    struct ab32_hwtimer *tim_device = RT_NULL;

    RT_ASSERT(timer != RT_NULL);
    tim = (hal_sfr_t)timer->parent.user_data;

    if (state)
    {
        tim_device = (struct ab32_hwtimer *)timer;

        if (timer->info->cntmode != HWTIMER_CNTMODE_UP)
        {
            LOG_E("Only support HWTIMER_CNTMODE_UP!");
        }

        /* set tim int */
        tim[TMRxCON] = BIT(7);

        LOG_D("%s init success", tim_device->name);
    } else {
        /* stop timer */
        tim[TMRxCON] = 0;
    }
}

static rt_err_t timer_start(rt_hwtimer_t *timer, rt_uint32_t t, rt_hwtimer_mode_t opmode)
{
    rt_err_t result = RT_EOK;
    hal_sfr_t tim = RT_NULL;

    RT_ASSERT(timer != RT_NULL);

    tim = (hal_sfr_t)timer->parent.user_data;

    /* set tim cnt */
    tim[TMRxCNT] = 0;
    tim[TMRxPR] = t * (get_sysclk_nhz() / timer->freq) - 1;

    if (opmode != HWTIMER_MODE_PERIOD)
    {
        LOG_E("Opmode only support HWTIMER_MODE_PERIOD!");
        return -RT_EINVAL;
    }

    /* start timer */
    tim[TMRxCON] |= BIT(0);

    return result;
}

static void timer_stop(rt_hwtimer_t *timer)
{
    hal_sfr_t tim = RT_NULL;

    RT_ASSERT(timer != RT_NULL);

    tim = (hal_sfr_t)timer->parent.user_data;

    /* stop timer */
    tim[TMRxCON] &= ~BIT(0);

    /* set tim cnt */
    tim[TMRxCNT] = 0;
}

static rt_err_t timer_ctrl(rt_hwtimer_t *timer, rt_uint32_t cmd, void *arg)
{
    hal_sfr_t tim = RT_NULL;
    rt_err_t result = RT_EOK;

    RT_ASSERT(timer != RT_NULL);
    RT_ASSERT(arg != RT_NULL);

    tim = (hal_sfr_t)timer->parent.user_data;

    switch (cmd)
    {
    case HWTIMER_CTRL_FREQ_SET:
    {
    }
    break;
    default:
    {
        result = -RT_ENOSYS;
    }
    break;
    }

    return result;
}

static rt_uint32_t timer_counter_get(rt_hwtimer_t *timer)
{
    hal_sfr_t tim = RT_NULL;

    RT_ASSERT(timer != RT_NULL);

    tim = (hal_sfr_t)timer->parent.user_data;

    return tim[TMRxCNT] / (get_sysclk_nhz() / timer->freq);
}

static const struct rt_hwtimer_info _info = TIM_DEV_INFO_CONFIG;

static const struct rt_hwtimer_ops _ops =
{
    .init = timer_init,
    .start = timer_start,
    .stop = timer_stop,
    .count_get = timer_counter_get,
    .control = timer_ctrl,
};

#if defined(BSP_USING_TIM2) || defined(BSP_USING_TIM4) || defined(BSP_USING_TIM5)
G
greedyhao 已提交
219
RT_SECTION(".irq.timer")
G
greedyhao 已提交
220 221 222 223 224 225
void timer2_4_5_isr(int vector, void *param)
{
    rt_interrupt_enter();
#ifdef BSP_USING_TIM2
    if (ab32_hwtimer_obj[TIM2_INDEX].tim_handle[TMRxCON] != 0) {
        ab32_hwtimer_obj[TIM2_INDEX].tim_handle[TMRxCPND] = BIT(9);
G
greedyhao 已提交
226
        _rt_device_hwtimer_isr(&ab32_hwtimer_obj[TIM2_INDEX].time_device);
G
greedyhao 已提交
227 228 229 230 231
    }
#endif
#ifdef BSP_USING_TIM4
    if (ab32_hwtimer_obj[TIM4_INDEX].tim_handle[TMRxCON] != 0) {
        ab32_hwtimer_obj[TIM4_INDEX].tim_handle[TMRxCPND] = BIT(9);
G
greedyhao 已提交
232
        _rt_device_hwtimer_isr(&ab32_hwtimer_obj[TIM4_INDEX].time_device);
G
greedyhao 已提交
233 234 235 236 237
    }
#endif
#ifdef BSP_USING_TIM5
    if (ab32_hwtimer_obj[TIM5_INDEX].tim_handle[TMRxCON] != 0) {
        ab32_hwtimer_obj[TIM5_INDEX].tim_handle[TMRxCPND] = BIT(9);
G
greedyhao 已提交
238
        _rt_device_hwtimer_isr(&ab32_hwtimer_obj[TIM5_INDEX].time_device);
G
greedyhao 已提交
239 240 241 242 243 244 245
    }
#endif
    rt_interrupt_leave();
}
#endif

#ifdef BSP_USING_TIM3
G
greedyhao 已提交
246
RT_SECTION(".irq.timer")
G
greedyhao 已提交
247 248 249 250
void timer3_isr(int vector, void *param)
{
    rt_interrupt_enter();
    ab32_hwtimer_obj[TIM3_INDEX].tim_handle[TMRxCPND] = BIT(9);
G
greedyhao 已提交
251
    _rt_device_hwtimer_isr(&ab32_hwtimer_obj[TIM3_INDEX].time_device);
G
greedyhao 已提交
252 253 254 255 256
    rt_interrupt_leave();
}
#endif

#ifdef BSP_USING_TIM1
G
greedyhao 已提交
257
RT_SECTION(".irq.timer")
G
greedyhao 已提交
258 259 260 261
void timer1_isr(int vector, void *param)
{
    rt_interrupt_enter();
    ab32_hwtimer_obj[TIM1_INDEX].tim_handle[TMRxCPND] = BIT(9);
G
greedyhao 已提交
262
    _rt_device_hwtimer_isr(&ab32_hwtimer_obj[TIM1_INDEX].time_device);
G
greedyhao 已提交
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
    rt_interrupt_leave();
}
#endif

static int ab32_hwtimer_init(void)
{
    int i = 0;
    int result = RT_EOK;

    for (i = 0; i < sizeof(ab32_hwtimer_obj) / sizeof(ab32_hwtimer_obj[0]); i++)
    {
        ab32_hwtimer_obj[i].time_device.info = &_info;
        ab32_hwtimer_obj[i].time_device.ops  = &_ops;
        if (rt_device_hwtimer_register(&ab32_hwtimer_obj[i].time_device, ab32_hwtimer_obj[i].name, (void *)ab32_hwtimer_obj[i].tim_handle) == RT_EOK)
        {
            LOG_D("%s register success", ab32_hwtimer_obj[i].name);
        }
        else
        {
            LOG_E("%s register failed", ab32_hwtimer_obj[i].name);
            result = -RT_ERROR;
        }
    }

#ifdef BSP_USING_TIM1
    rt_hw_interrupt_install(IRQ_TMR1_VECTOR, timer1_isr, RT_NULL, "t1_isr");
#endif
#if defined(BSP_USING_TIM2) || defined(BSP_USING_TIM4) || defined(BSP_USING_TIM5)
    rt_hw_interrupt_install(IRQ_TMR2_4_5_VECTOR, timer2_4_5_isr, RT_NULL, "t245_isr");
#endif
#ifdef BSP_USING_TIM3
    rt_hw_interrupt_install(IRQ_IRRX_VECTOR, timer3_isr, RT_NULL, "t3_isr");
#endif

    return result;
}
INIT_BOARD_EXPORT(ab32_hwtimer_init);

#endif /* RT_USING_HWTIMER */
#endif /* BSP_USING_TIM */