summaryrefslogtreecommitdiff
path: root/bsp/stm32/libraries/HAL_Drivers/drivers/drv_lptim.c
blob: cfcf540531f48b94ae4d825c2f400cc9dc57f7c0 (plain)
1
2
3
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
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
102
103
104
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
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
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
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
/*
 * Copyright (c) 2006-2024 RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author          Notes
 * 2019-05-06     Zero-Free       first version
 * 2024-07-04     wdfk-prog       lptimer is register with clock_timer, only supports pm calls,the timer function is not supported
 */

#include <board.h>
#include <drv_lptim.h>
#include <rtdevice.h>
#include "drv_config.h"

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

#ifdef BSP_USING_LPTIM

#define LPTIM_REG_MAX_VALUE (0xFFFF)

enum
{
#ifdef BSP_USING_LPTIM1
    LPTIM1_INDEX,
#endif
#ifdef BSP_USING_LPTIM2
    LPTIM2_INDEX,
#endif
#ifdef BSP_USING_LPTIM3
    LPTIM3_INDEX,
#endif
};

struct stm32_hw_lptimer
{
    rt_clock_timer_t        time_device;
    LPTIM_HandleTypeDef tim_handle;
    IRQn_Type           tim_irqn;
    char                *name;
};

static struct stm32_hw_lptimer stm32_hw_lptimer_obj[] =
{
#ifdef BSP_USING_LPTIM1
    LPTIM1_CONFIG,
#endif
#ifdef BSP_USING_LPTIM2
    LPTIM2_CONFIG,
#endif
#ifdef BSP_USING_LPTIM3
    LPTIM3_CONFIG,
#endif
};

static const struct rt_clock_timer_info _info = LPTIM_DEV_INFO_CONFIG;

static void timer_init(struct rt_clock_timer_device *timer, rt_uint32_t state)
{
    if(timer == RT_NULL)
    {
        LOG_E("init timer is NULL");
        return;
    }

    if (state)
    {
        struct stm32_hw_lptimer *tim_device = rt_container_of(timer, struct stm32_hw_lptimer, time_device);
        LPTIM_HandleTypeDef *tim = (LPTIM_HandleTypeDef *)timer->parent.user_data;

        if(tim_device == RT_NULL)
        {
            LOG_E("start tim_device is NULL");
            return;
        }
        if(tim == RT_NULL)
        {
            LOG_E("start %s LPTIM_Handle is NULL", tim_device->name);
            return;
        }

        RCC_OscInitTypeDef RCC_OscInitStruct = {0};
        RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct = {0};

        /* Enable LSI clock */
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI;
        RCC_OscInitStruct.LSIState = RCC_LSI_ON;
        RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
        HAL_RCC_OscConfig(&RCC_OscInitStruct);

        /* Select the LSI clock as LPTIM peripheral clock */
        RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LPTIM1;
        RCC_PeriphCLKInitStruct.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_LSI;
        HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct);

        tim->Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC;
        tim->Init.Clock.Prescaler = LPTIM_PRESCALER_DIV32;
        tim->Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
        tim->Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
        tim->Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
        tim->Init.CounterSource = LPTIM_COUNTERSOURCE_INTERNAL;

        HAL_StatusTypeDef ret = HAL_LPTIM_Init(tim);
        if (ret != HAL_OK)
        {
            LOG_E("%s init failed %d", tim_device->name, ret);
        }
        else
        {
            NVIC_ClearPendingIRQ(LPTIM1_IRQn);
            NVIC_SetPriority(LPTIM1_IRQn, 0);
            NVIC_EnableIRQ(LPTIM1_IRQn);
            LOG_D("%s init success", tim_device->name);
        }
    }
}

static rt_err_t timer_start(rt_clock_timer_t *timer, rt_uint32_t t, rt_clock_timer_mode_t opmode)
{
    if(timer == RT_NULL)
    {
        LOG_E("start timer is NULL");
        return -RT_EINVAL;
    }

    struct stm32_hw_lptimer *tim_device = rt_container_of(timer, struct stm32_hw_lptimer, time_device);
    LPTIM_HandleTypeDef *tim = (LPTIM_HandleTypeDef *)timer->parent.user_data;

    if(tim_device == RT_NULL)
    {
        LOG_E("start tim_device is NULL");
        return -RT_EINVAL;
    }
    if(tim == RT_NULL)
    {
        LOG_E("start %s LPTIM_Handle is NULL", tim_device->name);
        return -RT_EINVAL;
    }

    HAL_StatusTypeDef ret = HAL_LPTIM_TimeOut_Start_IT(tim, LPTIM_REG_MAX_VALUE, t);
    if(ret != HAL_OK)
    {
        LOG_E("start %s failed %d", tim_device->name, ret);
        return -RT_ERROR;
    }
    else
    {
        LOG_D("start %s success", tim_device->name);
        return RT_EOK;
    }
}

static void timer_stop(rt_clock_timer_t *timer)
{
    if(timer == RT_NULL)
    {
        LOG_E("stop timer is NULL");
        return;
    }

    struct stm32_hw_lptimer *tim_device = rt_container_of(timer, struct stm32_hw_lptimer, time_device);
    LPTIM_HandleTypeDef *tim = (LPTIM_HandleTypeDef *)timer->parent.user_data;

    if(tim_device == RT_NULL)
    {
        LOG_E("stop tim_device is NULL");
        return;
    }
    if(tim == RT_NULL)
    {
        LOG_E("stop %s LPTIM_Handle is NULL", tim_device->name);
        return;
    }

    HAL_StatusTypeDef ret = HAL_LPTIM_TimeOut_Stop_IT(tim);
    if(ret != HAL_OK)
    {
        LOG_E("stop %s failed %d", tim_device->name, ret);
    }
    else
    {
        LOG_D("stop %s success", tim_device->name);
    }
}

static rt_uint32_t timer_get_freq(LPTIM_HandleTypeDef *tim)
{
    /*No calculation is performed. The default initial configuration is 1000hz*/
    return 1000;
}


static rt_uint32_t timer_counter_get(rt_clock_timer_t *timer)
{
    LPTIM_HandleTypeDef *tim = (LPTIM_HandleTypeDef *)timer->parent.user_data;
    return HAL_LPTIM_ReadCounter(tim);
}

static rt_err_t timer_ctrl(rt_clock_timer_t *timer, rt_uint32_t cmd, void *arg)
{
    if(timer == RT_NULL)
    {
        LOG_E("start timer is NULL");
        return -RT_EINVAL;
    }

    struct stm32_hw_lptimer *tim_device = rt_container_of(timer, struct stm32_hw_lptimer, time_device);
    LPTIM_HandleTypeDef *tim = (LPTIM_HandleTypeDef *)timer->parent.user_data;

    if(tim_device == RT_NULL)
    {
        LOG_E("start tim_device is NULL");
        return -RT_EINVAL;
    }
    if(tim == RT_NULL)
    {
        LOG_E("start %s LPTIM_Handle is NULL", tim_device->name);
        return -RT_EINVAL;
    }

    rt_err_t result = RT_EOK;
    switch (cmd)
    {
        case DRV_HW_LPTIMER_CTRL_GET_TICK_MAX:
        {
            *(rt_uint32_t *)arg = LPTIM_REG_MAX_VALUE;
            break;
        }
        case DRV_HW_LPTIMER_CTRL_GET_FREQ:
        {
            *(rt_uint32_t *)arg = timer_get_freq(tim);
            break;
        }
        case DRV_HW_LPTIMER_CTRL_START:
        {
            timer_start(timer, *(rt_uint32_t *)arg, CLOCK_TIMER_MODE_ONESHOT);
            break;
        }
        case DRV_HW_LPTIMER_CTRL_GET_COUNT:
        {
            *(rt_uint32_t *)arg = timer_counter_get(timer);
            break;
        }
        default:
        {
            result = -RT_ENOSYS;
        }
        break;
    }

    return result;
}

#ifdef BSP_USING_LPTIM1
void LPTIM1_IRQHandler(void)
{
    rt_interrupt_enter();
    HAL_LPTIM_IRQHandler(&stm32_hw_lptimer_obj[LPTIM1_INDEX].tim_handle);
    rt_interrupt_leave();
}
#endif

#ifdef BSP_USING_LPTIM2
void LPTIM2_IRQHandler(void)
{
    rt_interrupt_enter();
    HAL_LPTIM_IRQHandler(&stm32_hw_lptimer_obj[LPTIM2_INDEX].tim_handle);
    rt_interrupt_leave();
}
#endif

#ifdef BSP_USING_LPTIM3
void LPTIM3_IRQHandler(void)
{
    rt_interrupt_enter();
    HAL_LPTIM_IRQHandler(&stm32_hw_lptimer_obj[LPTIM3_INDEX].tim_handle);
    rt_interrupt_leave();
}
#endif

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

/**
 * This function initialize the lptim
 */
static int stm32_hw_lptim_init(void)
{
    int i = 0;
    int result = RT_EOK;

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

    return result;
}

INIT_BOARD_EXPORT(stm32_hw_lptim_init);
#endif /* BSP_USING_LPTIM */