1 /*
2 * Copyright (c) 2015 - 2023, 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 nrfy_qdec_shorts_enable(p_instance->p_reg, NRF_QDEC_SHORT_REPORTRDY_READCLRACC_MASK);
96
97 uint32_t int_mask = NRF_QDEC_INT_ACCOF_MASK;
98
99 if (p_config->reportper_inten)
100 {
101 int_mask |= NRF_QDEC_INT_REPORTRDY_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_instance);
116 NRFX_ASSERT(p_config);
117 NRFX_ASSERT(handler);
118
119 qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
120
121 nrfx_err_t err_code;
122
123 if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
124 {
125 err_code = NRFX_ERROR_INVALID_STATE;
126 NRFX_LOG_WARNING("Function: %s, error code: %s.",
127 __func__,
128 NRFX_LOG_ERROR_STRING_GET(err_code));
129 return err_code;
130 }
131
132 p_cb->handler = handler;
133 p_cb->p_context = p_context;
134
135 if (p_config)
136 {
137 p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
138 qdec_configure(p_instance, p_config);
139 }
140
141 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
142
143 err_code = NRFX_SUCCESS;
144 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
145 return err_code;
146 }
147
nrfx_qdec_reconfigure(nrfx_qdec_t const * p_instance,nrfx_qdec_config_t const * p_config)148 nrfx_err_t nrfx_qdec_reconfigure(nrfx_qdec_t const * p_instance,
149 nrfx_qdec_config_t const * p_config)
150 {
151 NRFX_ASSERT(p_config);
152 qdec_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
153
154 if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
155 {
156 return NRFX_ERROR_INVALID_STATE;
157 }
158 if (p_cb->state == NRFX_DRV_STATE_POWERED_ON)
159 {
160 return NRFX_ERROR_BUSY;
161 }
162 qdec_configure(p_instance, p_config);
163 nrfy_qdec_enable(p_instance->p_reg);
164 return NRFX_SUCCESS;
165 }
166
nrfx_qdec_uninit(nrfx_qdec_t const * p_instance)167 void nrfx_qdec_uninit(nrfx_qdec_t const * p_instance)
168 {
169 NRFX_ASSERT(p_instance);
170 qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
171 nrfy_qdec_pins_t pins;
172
173 NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
174
175 nrfy_qdec_disable(p_instance->p_reg);
176 nrfy_qdec_int_uninit(p_instance->p_reg);
177
178 nrfy_qdec_shorts_disable(p_instance->p_reg, NRF_QDEC_SHORT_REPORTRDY_READCLRACC_MASK);
179 if (!p_cb->skip_gpio_cfg)
180 {
181 nrfy_qdec_pins_get(p_instance->p_reg, &pins);
182 nrfy_gpio_cfg_default(pins.a_pin);
183 nrfy_gpio_cfg_default(pins.b_pin);
184
185 uint32_t led_pin = nrfy_qdec_led_pin_get(p_instance->p_reg);
186 if (led_pin != NRF_QDEC_PIN_NOT_CONNECTED)
187 {
188 nrfy_gpio_cfg_default(led_pin);
189 }
190 }
191
192 p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
193 NRFX_LOG_INFO("Uninitialized.");
194 }
195
nrfx_qdec_enable(nrfx_qdec_t const * p_instance)196 void nrfx_qdec_enable(nrfx_qdec_t const * p_instance)
197 {
198 NRFX_ASSERT(p_instance);
199
200 qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
201
202 NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
203
204 nrfy_qdec_enable(p_instance->p_reg);
205 nrfy_qdec_task_trigger(p_instance->p_reg, NRF_QDEC_TASK_START);
206 p_cb->state = NRFX_DRV_STATE_POWERED_ON;
207 NRFX_LOG_INFO("Enabled.");
208 }
209
nrfx_qdec_disable(nrfx_qdec_t const * p_instance)210 void nrfx_qdec_disable(nrfx_qdec_t const * p_instance)
211 {
212 NRFX_ASSERT(p_instance);
213
214 qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
215
216 NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_POWERED_ON);
217 nrfy_qdec_task_trigger(p_instance->p_reg, NRF_QDEC_TASK_STOP);
218 nrfy_qdec_disable(p_instance->p_reg);
219 p_cb->state = NRFX_DRV_STATE_INITIALIZED;
220 NRFX_LOG_INFO("Disabled.");
221 }
222
nrfx_qdec_accumulators_read(nrfx_qdec_t const * p_instance,int32_t * p_acc,uint32_t * p_accdbl)223 void nrfx_qdec_accumulators_read(nrfx_qdec_t const * p_instance,
224 int32_t * p_acc,
225 uint32_t * p_accdbl)
226 {
227 NRFX_ASSERT(p_instance);
228 NRFX_ASSERT(p_accdbl);
229 NRFX_ASSERT(p_acc);
230 NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_POWERED_ON);
231
232 nrfy_qdec_task_trigger(p_instance->p_reg, NRF_QDEC_TASK_READCLRACC);
233 nrfy_qdec_accumulators_read(p_instance->p_reg, p_acc, p_accdbl);
234
235 NRFX_LOG_DEBUG("Accumulators data, ACC register:");
236 NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_acc, sizeof(p_acc[0]));
237 NRFX_LOG_DEBUG("Accumulators data, ACCDBL register:");
238 NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_accdbl, sizeof(p_accdbl[0]));
239 }
240
irq_handler(NRF_QDEC_Type * p_qdec,qdec_control_block_t * p_cb)241 static void irq_handler(NRF_QDEC_Type * p_qdec, qdec_control_block_t * p_cb)
242 {
243 uint32_t evt_to_process;
244 nrfx_qdec_event_t event;
245 uint32_t evt_mask;
246
247 evt_to_process = NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_SAMPLERDY) |
248 NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_REPORTRDY) |
249 NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_ACCOF);
250
251 evt_mask = nrfy_qdec_events_process(p_qdec, evt_to_process);
252
253 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_SAMPLERDY))
254 {
255 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_SAMPLERDY));
256
257 event.type = NRF_QDEC_EVENT_SAMPLERDY;
258 event.data.sample.value = (int8_t)nrfy_qdec_sample_get(p_qdec);
259 p_cb->handler(event, p_cb->p_context);
260 }
261
262 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_REPORTRDY))
263 {
264 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_REPORTRDY));
265
266 event.type = NRF_QDEC_EVENT_REPORTRDY;
267 nrfy_qdec_accumulators_read(p_qdec, &event.data.report.acc, &event.data.report.accdbl);
268 p_cb->handler(event, p_cb->p_context);
269 }
270
271 if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_ACCOF))
272 {
273 NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_ACCOF));
274
275 event.type = NRF_QDEC_EVENT_ACCOF;
276 p_cb->handler(event, p_cb->p_context);
277 }
278 }
279
280 NRFX_INSTANCE_IRQ_HANDLERS(QDEC, qdec)
281
282 #endif // NRFX_CHECK(NRFX_QDEC_ENABLED)
283