1 /**
2 * \file
3 *
4 * \brief SAM QUAD DECODER Driver for SAMB11
5 *
6 * Copyright (C) 2015-2016 Atmel Corporation. All rights reserved.
7 *
8 * \asf_license_start
9 *
10 * \page License
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 *
18 * 2. Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 *
22 * 3. The name of Atmel may not be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * 4. This software may only be redistributed and used in connection with an
26 * Atmel microcontroller product.
27 *
28 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 *
40 * \asf_license_stop
41 *
42 */
43 /*
44 * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45 */
46 #include "quad_decoder.h"
47
48 static quad_decoder_callback_t quad_decoder0_callback = NULL;
49 static quad_decoder_callback_t quad_decoder1_callback = NULL;
50 static quad_decoder_callback_t quad_decoder2_callback = NULL;
51
52 /**
53 * \brief Initializes config with predefined default values.
54 *
55 * This function will initialize a given QUAD DECODER configuration structure to
56 * a set of known default values. This function should be called on
57 * any new instance of the configuration structures before being
58 * modified by the user application.
59 *
60 * The default configuration is as follows:
61 * \li Select input clock as 26MHz
62 * \li Set counter upper threshold as 32767
63 * \li Set counter lower threshold as -32768
64 * \li Set pinmux_pad[0] as 0
65 * \li Set pinmux_pad[1] as 0
66 *
67 * \param[out] config Pointer to a QUAD DECODER module configuration structure to set
68 */
quad_decoder_get_config_defaults(struct quad_decoder_config * config)69 void quad_decoder_get_config_defaults(struct quad_decoder_config *config)
70 {
71 /* Axis X */
72 config->qdec0.clock_sel = QDEC_CLK_INPUT_0;
73 config->qdec0.threshold_upper = 32767;
74 config->qdec0.threshold_lower = -32768;
75 config->qdec0.pin_number_pad[0] = 0;
76 config->qdec0.pin_number_pad[1] = 0;
77 config->qdec0.pinmux_sel_pad[0] = 0;
78 config->qdec0.pinmux_sel_pad[1] = 0;
79 config->qdec_enalbe = (1 << QDEC_AXIS_X);
80 /* Axis Y */
81 config->qdec1.clock_sel = QDEC_CLK_INPUT_0;
82 config->qdec1.threshold_upper = 32767;
83 config->qdec1.threshold_lower = -32768;
84 config->qdec1.pin_number_pad[0] = 0;
85 config->qdec1.pin_number_pad[1] = 0;
86 config->qdec1.pinmux_sel_pad[0] = 0;
87 config->qdec1.pinmux_sel_pad[1] = 0;
88 config->qdec_enalbe |= (1 << QDEC_AXIS_Y);
89 /* Axis Z */
90 config->qdec2.clock_sel = QDEC_CLK_INPUT_0;
91 config->qdec2.threshold_upper = 32767;
92 config->qdec2.threshold_lower = -32768;
93 config->qdec2.pin_number_pad[0] = 0;
94 config->qdec2.pin_number_pad[1] = 0;
95 config->qdec2.pinmux_sel_pad[0] = 0;
96 config->qdec2.pinmux_sel_pad[1] = 0;
97 config->qdec_enalbe |= (1 << QDEC_AXIS_Z);
98 }
99
100 /**
101 * \brief Quad Decoder ISR handler.
102 *
103 * Quad Decoder ISR handler.
104 *
105 */
quad_decoder_isr_handler(void)106 static void quad_decoder_isr_handler(void)
107 {
108 uint8_t status = LPMCU_MISC_REGS0->QUAD_DEC_IRQS.reg;
109
110 if (status & LPMCU_MISC_REGS_QUAD_DEC_IRQS_QUAD_DEC0_IRQ) {
111 LPMCU_MISC_REGS0->QUAD_DEC0_CTRL.reg |=
112 LPMCU_MISC_REGS_QUAD_DEC0_CTRL_CLR_IRQ;
113 if (quad_decoder0_callback) {
114 quad_decoder0_callback();
115 }
116 }
117
118 if (status & LPMCU_MISC_REGS_QUAD_DEC_IRQS_QUAD_DEC1_IRQ) {
119 LPMCU_MISC_REGS0->QUAD_DEC1_CTRL.reg |=
120 LPMCU_MISC_REGS_QUAD_DEC1_CTRL_CLR_IRQ;
121 if (quad_decoder1_callback) {
122 quad_decoder1_callback();
123 }
124 }
125
126 if (status & LPMCU_MISC_REGS_QUAD_DEC_IRQS_QUAD_DEC2_IRQ) {
127 LPMCU_MISC_REGS0->QUAD_DEC2_CTRL.reg |=
128 LPMCU_MISC_REGS_QUAD_DEC2_CTRL_CLR_IRQ;
129 if (quad_decoder2_callback) {
130 quad_decoder2_callback();
131 }
132 }
133 }
134
135 /**
136 * \brief Initializes QUAD DECODER module instance.
137 *
138 * Initializes the QUAD DECODER module, based on the given
139 * configuration values.
140 *
141 * \param[in] qdec Axis(x,y,z) of QUAD DECODER instance
142 * \param[in] config Pointer to the QAUD DECODER configuration options struct
143 */
quad_decoder_init(const struct quad_decoder_config * config)144 void quad_decoder_init(const struct quad_decoder_config *config)
145 {
146 if (config->qdec_enalbe & (1 << QDEC_AXIS_X)) {
147 system_peripheral_reset(PERIPHERAL_QDEC0);
148 LPMCU_MISC_REGS0->QUAD_DEC0_CTRL.bit.CLOCK_SEL = config->qdec0.clock_sel;
149 LPMCU_MISC_REGS0->QUAD_DEC0_THRESHOLD.bit.UPPER = config->qdec0.threshold_upper;
150 LPMCU_MISC_REGS0->QUAD_DEC0_THRESHOLD.bit.LOWER = config->qdec0.threshold_lower;
151 gpio_pinmux_cofiguration(config->qdec0.pin_number_pad[0],
152 (uint16_t)(config->qdec0.pinmux_sel_pad[0]));
153 gpio_pinmux_cofiguration(config->qdec0.pin_number_pad[1],
154 (uint16_t)(config->qdec0.pinmux_sel_pad[1]));
155 quad_decoder_enable(QDEC_AXIS_X);
156 }
157 if (config->qdec_enalbe & (1 << QDEC_AXIS_Y)) {
158 system_peripheral_reset(PERIPHERAL_QDEC1);
159 LPMCU_MISC_REGS0->QUAD_DEC1_CTRL.bit.CLOCK_SEL = config->qdec1.clock_sel;
160 LPMCU_MISC_REGS0->QUAD_DEC1_THRESHOLD.bit.UPPER = config->qdec1.threshold_upper;
161 LPMCU_MISC_REGS0->QUAD_DEC1_THRESHOLD.bit.LOWER = config->qdec1.threshold_lower;
162 gpio_pinmux_cofiguration(config->qdec1.pin_number_pad[0],
163 (uint16_t)(config->qdec1.pinmux_sel_pad[0]));
164 gpio_pinmux_cofiguration(config->qdec1.pin_number_pad[1],
165 (uint16_t)(config->qdec1.pinmux_sel_pad[1]));
166 quad_decoder_enable(QDEC_AXIS_Y);
167 }
168 if (config->qdec_enalbe & (1 << QDEC_AXIS_Z)) {
169 system_peripheral_reset(PERIPHERAL_QDEC2);
170 LPMCU_MISC_REGS0->QUAD_DEC2_CTRL.bit.CLOCK_SEL = config->qdec2.clock_sel;
171 LPMCU_MISC_REGS0->QUAD_DEC2_THRESHOLD.bit.UPPER = config->qdec2.threshold_upper;
172 LPMCU_MISC_REGS0->QUAD_DEC2_THRESHOLD.bit.LOWER = config->qdec2.threshold_lower;
173 gpio_pinmux_cofiguration(config->qdec2.pin_number_pad[0],
174 (uint16_t)(config->qdec2.pinmux_sel_pad[0]));
175 gpio_pinmux_cofiguration(config->qdec2.pinmux_sel_pad[1],
176 (uint16_t)(config->qdec2.pinmux_sel_pad[1]));
177 quad_decoder_enable(QDEC_AXIS_Z);
178 }
179 LPMCU_MISC_REGS0->IRQ_MUX_IO_SEL_4.bit.MUX_18 = LPMCU_MISC_REGS_IRQ_MUX_IO_SEL_4_MUX_18_19_Val;
180 system_register_isr(33, (uint32_t)quad_decoder_isr_handler);
181 }
182
183 /**
184 * \brief Enable QUAD DECODER module instance.
185 *
186 * Enable the QUAD DECODER module instance, based on the given axis
187 *
188 * \param[in] qdec Axis(x,y,z) of QUAD DECODER instance
189 */
quad_decoder_enable(enum quad_decoder_axis qdec)190 void quad_decoder_enable(enum quad_decoder_axis qdec)
191 {
192 switch (qdec) {
193 case QDEC_AXIS_X:
194 LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg |=
195 LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC0_CLK_EN;
196 LPMCU_MISC_REGS0->QUAD_DEC0_CTRL.reg |=
197 LPMCU_MISC_REGS_QUAD_DEC0_CTRL_ENABLE;
198 break;
199 case QDEC_AXIS_Y:
200 LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg |=
201 LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC1_CLK_EN;
202 LPMCU_MISC_REGS0->QUAD_DEC1_CTRL.reg |=
203 LPMCU_MISC_REGS_QUAD_DEC1_CTRL_ENABLE;
204 break;
205 case QDEC_AXIS_Z:
206 LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg |=
207 LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC2_CLK_EN;
208 LPMCU_MISC_REGS0->QUAD_DEC2_CTRL.reg |=
209 LPMCU_MISC_REGS_QUAD_DEC2_CTRL_ENABLE;
210 break;
211 }
212 }
213
214 /**
215 * \brief Disable QUAD DECODER module instance.
216 *
217 * Disable the QUAD DECODER module instance, based on the given axis
218 *
219 * \param[in] qdec Axis(x,y,z) of QUAD DECODER instance
220 */
quad_decoder_disable(enum quad_decoder_axis qdec)221 void quad_decoder_disable(enum quad_decoder_axis qdec)
222 {
223 switch (qdec) {
224 case QDEC_AXIS_X:
225 LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg &=
226 ~LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC0_CLK_EN;
227 LPMCU_MISC_REGS0->QUAD_DEC0_CTRL.reg &=
228 ~LPMCU_MISC_REGS_QUAD_DEC0_CTRL_ENABLE;
229 break;
230 case QDEC_AXIS_Y:
231 LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg &=
232 ~LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC1_CLK_EN;
233 LPMCU_MISC_REGS0->QUAD_DEC1_CTRL.reg &=
234 ~LPMCU_MISC_REGS_QUAD_DEC1_CTRL_ENABLE;
235 break;
236 case QDEC_AXIS_Z:
237 LPMCU_MISC_REGS0->LPMCU_CLOCK_ENABLES_0.reg &=
238 ~LPMCU_MISC_REGS_LPMCU_CLOCK_ENABLES_0_QUAD_DEC2_CLK_EN;
239 LPMCU_MISC_REGS0->QUAD_DEC2_CTRL.reg &=
240 ~LPMCU_MISC_REGS_QUAD_DEC2_CTRL_ENABLE;
241 break;
242 }
243 }
244
245 /**
246 * \brief Get QUAD DECODER current counter
247 *
248 * Get the current counter of quad decoder, based on the given axis
249 *
250 * \param[in] qdec Axis(x,y,z) of QUAD DECODER instance
251 *
252 * \return The current counter of quad decoder instance
253 */
quad_decoder_get_counter(enum quad_decoder_axis qdec)254 int16_t quad_decoder_get_counter(enum quad_decoder_axis qdec)
255 {
256 switch (qdec) {
257 case QDEC_AXIS_X:
258 return LPMCU_MISC_REGS0->QUAD_DEC0_STATUS.bit.COUNT;
259 case QDEC_AXIS_Y:
260 return LPMCU_MISC_REGS0->QUAD_DEC1_STATUS.bit.COUNT;
261 case QDEC_AXIS_Z:
262 return LPMCU_MISC_REGS0->QUAD_DEC2_STATUS.bit.COUNT;
263 }
264 return 0;
265 }
266
267 /**
268 * \brief Registers a callback.
269 *
270 * Registers and enable a callback function which is implemented by the user.
271 *
272 * \param[in] callback_func Pointer to callback function
273 */
quad_decoder_register_callback(enum quad_decoder_axis qdec,quad_decoder_callback_t fun)274 void quad_decoder_register_callback(enum quad_decoder_axis qdec, quad_decoder_callback_t fun)
275 {
276 switch (qdec) {
277 case QDEC_AXIS_X:
278 quad_decoder0_callback = fun;
279 break;
280 case QDEC_AXIS_Y:
281 quad_decoder1_callback = fun;
282 break;
283 case QDEC_AXIS_Z:
284 quad_decoder2_callback = fun;
285 break;
286 }
287 }
288
289 /**
290 * \brief Unregisters a callback.
291 *
292 * Unregisters and disable a callback function implemented by the user.
293 *
294 */
quad_decoder_unregister_callback(enum quad_decoder_axis qdec)295 void quad_decoder_unregister_callback(enum quad_decoder_axis qdec)
296 {
297 switch (qdec) {
298 case QDEC_AXIS_X:
299 quad_decoder0_callback = NULL;
300 break;
301 case QDEC_AXIS_Y:
302 quad_decoder1_callback = NULL;
303 break;
304 case QDEC_AXIS_Z:
305 quad_decoder2_callback = NULL;
306 break;
307 }
308 }