1 /*
2 * Copyright (c) 2022, Valerio Setti <vsetti@baylibre.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT st_stm32_qdec
8
9 /** @file
10 * @brief STM32 family Quadrature Decoder (QDEC) driver.
11 */
12
13 #include <errno.h>
14
15 #include <zephyr/sys/__assert.h>
16 #include <zephyr/sys/util.h>
17 #include <zephyr/device.h>
18 #include <zephyr/init.h>
19 #include <zephyr/drivers/sensor.h>
20 #include <zephyr/drivers/pinctrl.h>
21 #include <zephyr/drivers/clock_control/stm32_clock_control.h>
22 #include <zephyr/logging/log.h>
23
24 #include <stm32_ll_tim.h>
25
26 LOG_MODULE_REGISTER(qdec_stm32, CONFIG_SENSOR_LOG_LEVEL);
27
28 /* Device constant configuration parameters */
29 struct qdec_stm32_dev_cfg {
30 const struct pinctrl_dev_config *pin_config;
31 struct stm32_pclken pclken;
32 TIM_TypeDef *timer_inst;
33 uint32_t encoder_mode;
34 bool is_input_polarity_inverted;
35 uint8_t input_filtering_level;
36 uint32_t counts_per_revolution;
37 };
38
39 /* Device run time data */
40 struct qdec_stm32_dev_data {
41 int32_t position;
42 };
43
qdec_stm32_fetch(const struct device * dev,enum sensor_channel chan)44 static int qdec_stm32_fetch(const struct device *dev, enum sensor_channel chan)
45 {
46 struct qdec_stm32_dev_data *dev_data = dev->data;
47 const struct qdec_stm32_dev_cfg *dev_cfg = dev->config;
48 uint32_t counter_value;
49
50 if ((chan != SENSOR_CHAN_ALL) && (chan != SENSOR_CHAN_ROTATION)) {
51 return -ENOTSUP;
52 }
53
54 /* We're only interested in the remainder between the current counter value and
55 * counts_per_revolution. The integer part represents an entire rotation so it
56 * can be ignored
57 */
58 counter_value = LL_TIM_GetCounter(dev_cfg->timer_inst) % dev_cfg->counts_per_revolution;
59 dev_data->position = (counter_value * 360) / dev_cfg->counts_per_revolution;
60
61 return 0;
62 }
63
qdec_stm32_get(const struct device * dev,enum sensor_channel chan,struct sensor_value * val)64 static int qdec_stm32_get(const struct device *dev, enum sensor_channel chan,
65 struct sensor_value *val)
66 {
67 struct qdec_stm32_dev_data *const dev_data = dev->data;
68
69 if (chan == SENSOR_CHAN_ROTATION) {
70 val->val1 = dev_data->position;
71 val->val2 = 0;
72 } else {
73 return -ENOTSUP;
74 }
75
76 return 0;
77 }
78
qdec_stm32_initialize(const struct device * dev)79 static int qdec_stm32_initialize(const struct device *dev)
80 {
81 const struct qdec_stm32_dev_cfg *const dev_cfg = dev->config;
82 int retval;
83 LL_TIM_ENCODER_InitTypeDef init_props;
84 uint32_t max_counter_value;
85
86 retval = pinctrl_apply_state(dev_cfg->pin_config, PINCTRL_STATE_DEFAULT);
87 if (retval < 0) {
88 return retval;
89 }
90
91 if (!device_is_ready(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE))) {
92 LOG_ERR("Clock control device not ready");
93 return -ENODEV;
94 }
95
96 retval = clock_control_on(DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE),
97 (clock_control_subsys_t)&dev_cfg->pclken);
98 if (retval < 0) {
99 LOG_ERR("Could not initialize clock");
100 return retval;
101 }
102
103 if (dev_cfg->counts_per_revolution < 1) {
104 LOG_ERR("Invalid number of counts per revolution (%d)",
105 dev_cfg->counts_per_revolution);
106 return -EINVAL;
107 }
108
109 LL_TIM_ENCODER_StructInit(&init_props);
110
111 init_props.EncoderMode = dev_cfg->encoder_mode;
112
113 if (dev_cfg->is_input_polarity_inverted) {
114 init_props.IC1Polarity = LL_TIM_IC_POLARITY_FALLING;
115 init_props.IC2Polarity = LL_TIM_IC_POLARITY_FALLING;
116 }
117
118 init_props.IC1Filter = dev_cfg->input_filtering_level * LL_TIM_IC_FILTER_FDIV1_N2;
119 init_props.IC2Filter = dev_cfg->input_filtering_level * LL_TIM_IC_FILTER_FDIV1_N2;
120
121 /* Ensure that the counter will always count up to a multiple of counts_per_revolution */
122 if (IS_TIM_32B_COUNTER_INSTANCE(dev_cfg->timer_inst)) {
123 max_counter_value = UINT32_MAX - (UINT32_MAX % dev_cfg->counts_per_revolution) - 1;
124 } else {
125 max_counter_value = UINT16_MAX - (UINT16_MAX % dev_cfg->counts_per_revolution) - 1;
126 }
127 LL_TIM_SetAutoReload(dev_cfg->timer_inst, max_counter_value);
128
129 if (LL_TIM_ENCODER_Init(dev_cfg->timer_inst, &init_props) != SUCCESS) {
130 LOG_ERR("Initalization failed");
131 return -EIO;
132 }
133
134 LL_TIM_EnableCounter(dev_cfg->timer_inst);
135
136 return 0;
137 }
138
139 static DEVICE_API(sensor, qdec_stm32_driver_api) = {
140 .sample_fetch = qdec_stm32_fetch,
141 .channel_get = qdec_stm32_get,
142 };
143
144 #define QDEC_STM32_INIT(n) \
145 BUILD_ASSERT(!(DT_INST_PROP(n, st_encoder_mode) & ~TIM_SMCR_SMS), \
146 "Encoder mode is not supported by this MCU"); \
147 \
148 PINCTRL_DT_INST_DEFINE(n); \
149 static const struct qdec_stm32_dev_cfg qdec##n##_stm32_config = { \
150 .pin_config = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
151 .timer_inst = ((TIM_TypeDef *)DT_REG_ADDR(DT_INST_PARENT(n))), \
152 .pclken = {.bus = DT_CLOCKS_CELL(DT_INST_PARENT(n), bus), \
153 .enr = DT_CLOCKS_CELL(DT_INST_PARENT(n), bits)}, \
154 .encoder_mode = DT_INST_PROP(n, st_encoder_mode), \
155 .is_input_polarity_inverted = DT_INST_PROP(n, st_input_polarity_inverted), \
156 .input_filtering_level = DT_INST_PROP(n, st_input_filter_level), \
157 .counts_per_revolution = DT_INST_PROP(n, st_counts_per_revolution), \
158 }; \
159 \
160 static struct qdec_stm32_dev_data qdec##n##_stm32_data; \
161 \
162 SENSOR_DEVICE_DT_INST_DEFINE(n, qdec_stm32_initialize, NULL, &qdec##n##_stm32_data, \
163 &qdec##n##_stm32_config, POST_KERNEL, \
164 CONFIG_SENSOR_INIT_PRIORITY, &qdec_stm32_driver_api);
165
166 DT_INST_FOREACH_STATUS_OKAY(QDEC_STM32_INIT)
167