1 /*
2 * Copyright (c) 2015 - 2025, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the copyright holder nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <nrfx.h>
35
36 #if NRFX_CHECK(NRFX_QDEC_ENABLED)
37
38 #include <nrfx_qdec.h>
39
40 #if !NRFX_FEATURE_PRESENT(NRFX_QDEC, _ENABLED)
41 #error "No enabled QDEC instances. Check <nrfx_config.h>."
42 #endif
43
44 #include <haly/nrfy_gpio.h>
45
46 #define NRFX_LOG_MODULE QDEC
47 #include <nrfx_log.h>
48
49 #define EVT_TO_STR(event) \
50 (event == NRF_QDEC_EVENT_SAMPLERDY ? "NRF_QDEC_EVENT_SAMPLERDY" : \
51 (event == NRF_QDEC_EVENT_REPORTRDY ? "NRF_QDEC_EVENT_REPORTRDY" : \
52 (event == NRF_QDEC_EVENT_ACCOF ? "NRF_QDEC_EVENT_ACCOF" : \
53 "UNKNOWN EVENT")))
54
55 // Control block - driver instance local data.
56 typedef struct
57 {
58 nrfx_drv_state_t state;
59 bool skip_gpio_cfg;
60 nrfx_qdec_event_handler_t handler;
61 void * p_context;
62 } qdec_control_block_t;
63
64 static qdec_control_block_t m_cb[NRFX_QDEC_ENABLED_COUNT];
65
qdec_configure(nrfx_qdec_t const * p_instance,nrfx_qdec_config_t const * p_config)66 static void qdec_configure(nrfx_qdec_t const * p_instance,
67 nrfx_qdec_config_t const * p_config)
68 {
69 if (!p_config->skip_gpio_cfg)
70 {
71 nrfy_gpio_cfg_input(p_config->psela, NRF_GPIO_PIN_NOPULL);
72 nrfy_gpio_cfg_input(p_config->pselb, NRF_GPIO_PIN_NOPULL);
73 if (p_config->pselled != NRF_QDEC_PIN_NOT_CONNECTED)
74 {
75 nrfy_gpio_cfg_input(p_config->pselled, NRF_GPIO_PIN_NOPULL);
76 }
77 }
78
79 nrfy_qdec_config_t nrfy_config =
80 {
81 .reportper = p_config->reportper,
82 .sampleper = p_config->sampleper,
83 .pins = {
84 .a_pin = p_config->psela,
85 .b_pin = p_config->pselb,
86 .led_pin = p_config->pselled
87 },
88 .ledpre = p_config->ledpre,
89 .ledpol = p_config->ledpol,
90 .dbfen = p_config->dbfen,
91 .skip_psel_cfg = p_config->skip_psel_cfg
92 };
93
94 nrfy_qdec_periph_configure(p_instance->p_reg, &nrfy_config);
95
96 uint32_t int_mask = NRF_QDEC_INT_ACCOF_MASK;
97
98 if (p_config->reportper_inten)
99 {
100 int_mask |= NRF_QDEC_INT_REPORTRDY_MASK;
101 nrfy_qdec_shorts_enable(p_instance->p_reg, NRF_QDEC_SHORT_REPORTRDY_READCLRACC_MASK);
102 }
103 if (p_config->sample_inten)
104 {
105 int_mask |= NRF_QDEC_INT_SAMPLERDY_MASK;
106 }
107 nrfy_qdec_int_init(p_instance->p_reg, int_mask, p_config->interrupt_priority, true);
108 }
109
nrfx_qdec_init(nrfx_qdec_t const * p_instance,nrfx_qdec_config_t const * p_config,nrfx_qdec_event_handler_t handler,void * p_context)110 nrfx_err_t nrfx_qdec_init(nrfx_qdec_t const * p_instance,
111 nrfx_qdec_config_t const * p_config,
112 nrfx_qdec_event_handler_t handler,
113 void * p_context)
114 {
115 NRFX_ASSERT(p_config);
116 NRFX_ASSERT(handler);
117
118 qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
119
120 nrfx_err_t err_code;
121
122 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
123 {
124 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
125 err_code = NRFX_ERROR_ALREADY;
126 #else
127 err_code = NRFX_ERROR_INVALID_STATE;
128 #endif
129 NRFX_LOG_WARNING("Function: %s, error code: %s.",
130 __func__,
131 NRFX_LOG_ERROR_STRING_GET(err_code));
132 return err_code;
133 }
134
135 p_cb->handler = handler;
136 p_cb->p_context = p_context;
137
138 if (p_config)
139 {
140 p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
141 qdec_configure(p_instance, p_config);
142 }
143
144 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
145
146 err_code = NRFX_SUCCESS;
147 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
148 return err_code;
149 }
150
nrfx_qdec_reconfigure(nrfx_qdec_t const * p_instance,nrfx_qdec_config_t const * p_config)151 nrfx_err_t nrfx_qdec_reconfigure(nrfx_qdec_t const * p_instance,
152 nrfx_qdec_config_t const * p_config)
153 {
154 NRFX_ASSERT(p_config);
155 qdec_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
156
157 if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
158 {
159 return NRFX_ERROR_INVALID_STATE;
160 }
161 if (p_cb->state == NRFX_DRV_STATE_POWERED_ON)
162 {
163 return NRFX_ERROR_BUSY;
164 }
165 qdec_configure(p_instance, p_config);
166 nrfy_qdec_enable(p_instance->p_reg);
167 return NRFX_SUCCESS;
168 }
169
nrfx_qdec_uninit(nrfx_qdec_t const * p_instance)170 void nrfx_qdec_uninit(nrfx_qdec_t const * p_instance)
171 {
172 qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
173 nrfy_qdec_pins_t pins;
174
175 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
176
177 nrfy_qdec_disable(p_instance->p_reg);
178 nrfy_qdec_int_disable(p_instance->p_reg, 0xFFFFFFFF);
179 nrfy_qdec_int_uninit(p_instance->p_reg);
180
181 nrfy_qdec_shorts_disable(p_instance->p_reg, NRF_QDEC_SHORT_REPORTRDY_READCLRACC_MASK);
182 if (!p_cb->skip_gpio_cfg)
183 {
184 nrfy_qdec_pins_get(p_instance->p_reg, &pins);
185 nrfy_gpio_cfg_default(pins.a_pin);
186 nrfy_gpio_cfg_default(pins.b_pin);
187
188 uint32_t led_pin = nrfy_qdec_led_pin_get(p_instance->p_reg);
189 if (led_pin != NRF_QDEC_PIN_NOT_CONNECTED)
190 {
191 nrfy_gpio_cfg_default(led_pin);
192 }
193 }
194
195 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
196 NRFX_LOG_INFO("Uninitialized.");
197 }
198
nrfx_qdec_init_check(nrfx_qdec_t const * p_instance)199 bool nrfx_qdec_init_check(nrfx_qdec_t const * p_instance)
200 {
201 qdec_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
202
203 return (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
204 }
205
nrfx_qdec_enable(nrfx_qdec_t const * p_instance)206 void nrfx_qdec_enable(nrfx_qdec_t const * p_instance)
207 {
208 qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
209
210 NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
211
212 nrfy_qdec_enable(p_instance->p_reg);
213 nrfy_qdec_task_trigger(p_instance->p_reg, NRF_QDEC_TASK_START);
214 p_cb->state = NRFX_DRV_STATE_POWERED_ON;
215 NRFX_LOG_INFO("Enabled.");
216 }
217
nrfx_qdec_disable(nrfx_qdec_t const * p_instance)218 void nrfx_qdec_disable(nrfx_qdec_t const * p_instance)
219 {
220 qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
221
222 NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_POWERED_ON);
223 nrfy_qdec_task_trigger(p_instance->p_reg, NRF_QDEC_TASK_STOP);
224 nrfy_qdec_disable(p_instance->p_reg);
225 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
226 NRFX_LOG_INFO("Disabled.");
227 }
228
nrfx_qdec_accumulators_read(nrfx_qdec_t const * p_instance,int32_t * p_acc,uint32_t * p_accdbl)229 void nrfx_qdec_accumulators_read(nrfx_qdec_t const * p_instance,
230 int32_t * p_acc,
231 uint32_t * p_accdbl)
232 {
233 NRFX_ASSERT(p_accdbl);
234 NRFX_ASSERT(p_acc);
235 NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_POWERED_ON);
236
237 nrfy_qdec_task_trigger(p_instance->p_reg, NRF_QDEC_TASK_READCLRACC);
238 nrfy_qdec_accumulators_read(p_instance->p_reg, p_acc, p_accdbl);
239
240 NRFX_LOG_DEBUG("Accumulators data, ACC register:");
241 NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_acc, sizeof(p_acc[0]));
242 NRFX_LOG_DEBUG("Accumulators data, ACCDBL register:");
243 NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_accdbl, sizeof(p_accdbl[0]));
244 }
245
irq_handler(NRF_QDEC_Type * p_qdec,qdec_control_block_t * p_cb)246 static void irq_handler(NRF_QDEC_Type * p_qdec, qdec_control_block_t * p_cb)
247 {
248 uint32_t evt_to_process;
249 nrfx_qdec_event_t event;
250 uint32_t evt_mask;
251 uint32_t all_evt_mask;
252
253 all_evt_mask = NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_SAMPLERDY) |
254 NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_REPORTRDY) |
255 NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_ACCOF);
256
257 evt_to_process = nrfy_qdec_int_enable_check(p_qdec, all_evt_mask);
258 evt_mask = nrfy_qdec_events_process(p_qdec, evt_to_process);
259
260 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_SAMPLERDY))
261 {
262 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_SAMPLERDY));
263
264 event.type = NRF_QDEC_EVENT_SAMPLERDY;
265 event.data.sample.value = (int8_t)nrfy_qdec_sample_get(p_qdec);
266 p_cb->handler(event, p_cb->p_context);
267 }
268
269 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_REPORTRDY))
270 {
271 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_REPORTRDY));
272
273 event.type = NRF_QDEC_EVENT_REPORTRDY;
274 nrfy_qdec_accumulators_read(p_qdec, &event.data.report.acc, &event.data.report.accdbl);
275 p_cb->handler(event, p_cb->p_context);
276 }
277
278 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_ACCOF))
279 {
280 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_ACCOF));
281
282 event.type = NRF_QDEC_EVENT_ACCOF;
283 p_cb->handler(event, p_cb->p_context);
284 }
285 }
286
287 NRFX_INSTANCE_IRQ_HANDLERS(QDEC, qdec)
288
289 #endif // NRFX_CHECK(NRFX_QDEC_ENABLED)
290