1 /**
2 * \file
3 *
4 * \brief SAM Timer Counter (TC) driver.
5 *
6 * Copyright (c) 2011-2015 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
47 #include <assert.h>
48 #include "tc.h"
49
50 /// @cond
51 /**INDENT-OFF**/
52 #ifdef __cplusplus
53 extern "C" {
54 #endif
55 /**INDENT-ON**/
56 /// @endcond
57
58 #ifndef TC_WPMR_WPKEY_PASSWD
59 #define TC_WPMR_WPKEY_PASSWD TC_WPMR_WPKEY((uint32_t)0x54494D)
60 #endif
61
62 /**
63 * \brief Configure TC for timer, waveform generation, or capture.
64 *
65 * \param[in,out] p_tc Module hardware register base address pointer
66 * \param[in] ul_channel Channel to configure
67 * \param[in] ul_mode Control mode register bitmask value to set
68 *
69 * \note For more information regarding <i>ul_mode</i> configuration refer to
70 * the section entitled "Channel Mode Register: Capture Mode" and/or section
71 * "Waveform Operating Mode" in the device-specific datasheet.
72 *
73 * \note If the TC is configured for waveform generation then the external event
74 * selection (EEVT) should only be set to TC_CMR_EEVT_TIOB, or the
75 * equivalent value of 0, if it really is the intention to use TIOB as an
76 * external event trigger. This is because this setting forces TIOB to be
77 * an input, even if the external event trigger has not been enabled with
78 * TC_CMR_ENETRG, and thus prevents normal operation of TIOB.
79 */
tc_init(Tc * p_tc,uint32_t ul_channel,uint32_t ul_mode)80 void tc_init(
81 Tc *p_tc,
82 uint32_t ul_channel,
83 uint32_t ul_mode)
84 {
85 TcChannel *tc_channel;
86
87 /* Validate inputs. */
88 Assert(p_tc);
89 Assert(ul_channel <
90 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
91 tc_channel = p_tc->TC_CHANNEL + ul_channel;
92
93 /* Disable TC clock. */
94 tc_channel->TC_CCR = TC_CCR_CLKDIS;
95
96 /* Disable interrupts. */
97 tc_channel->TC_IDR = 0xFFFFFFFF;
98
99 /* Clear status register. */
100 tc_channel->TC_SR;
101
102 /* Set mode. */
103 tc_channel->TC_CMR = ul_mode;
104 }
105
106 /**
107 * \brief Asserts a SYNC signal to generate a software trigger on
108 * all channels.
109 *
110 * \param[out] p_tc Module hardware register base address pointer
111 *
112 */
tc_sync_trigger(Tc * p_tc)113 void tc_sync_trigger(
114 Tc *p_tc)
115 {
116 /* Validate inputs. */
117 Assert(p_tc);
118
119 p_tc->TC_BCR = TC_BCR_SYNC;
120 }
121
122 /**
123 * \brief Configure the TC Block mode.
124 *
125 * \note The function tc_init() must be called prior to this one.
126 *
127 * \param[out] p_tc Module hardware register base address pointer
128 * \param[in] ul_blockmode Block mode register value to set
129 *
130 * \note For more information regarding <i>ul_blockmode</i> configuration refer to
131 * the section entitled "TC Block Mode Register" in the device-specific datasheet.
132 */
tc_set_block_mode(Tc * p_tc,uint32_t ul_blockmode)133 void tc_set_block_mode(
134 Tc *p_tc,
135 uint32_t ul_blockmode)
136 {
137 /* Validate inputs. */
138 Assert(p_tc);
139
140 p_tc->TC_BMR = ul_blockmode;
141 }
142
143 #if (!SAM3U) || defined(__DOXYGEN__)
144
145 /**
146 * \brief Configure TC for 2-bit Gray Counter for Stepper Motor.
147 * \note The function tc_init() must be called prior to this one.
148 *
149 * \note This function is not available on SAM3U devices.
150 *
151 * \param[out] p_tc Module hardware register base address pointer
152 * \param[in] ul_channel Channel to configure
153 * \param[in] ul_steppermode Stepper motor mode register value to set
154 *
155 * \return 0 for OK.
156 */
tc_init_2bit_gray(Tc * p_tc,uint32_t ul_channel,uint32_t ul_steppermode)157 uint32_t tc_init_2bit_gray(
158 Tc *p_tc,
159 uint32_t ul_channel,
160 uint32_t ul_steppermode)
161 {
162 /* Validate inputs. */
163 Assert(p_tc);
164 Assert(ul_channel <
165 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
166
167 p_tc->TC_CHANNEL[ul_channel].TC_SMMR = ul_steppermode;
168 return 0;
169 }
170
171 #endif /* (!SAM3U) || defined(__DOXYGEN__) */
172
173 /**
174 * \brief Start the TC clock on the specified channel.
175 *
176 * \param[out] p_tc Module hardware register base address pointer
177 * \param[in] ul_channel Channel to configure
178 */
tc_start(Tc * p_tc,uint32_t ul_channel)179 void tc_start(
180 Tc *p_tc,
181 uint32_t ul_channel)
182 {
183 /* Validate inputs. */
184 Assert(p_tc);
185 Assert(ul_channel <
186 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
187
188 p_tc->TC_CHANNEL[ul_channel].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;
189 }
190
191 /**
192 * \brief Stop the TC clock on the specified channel.
193 *
194 * \param[out] p_tc Module hardware register base address pointer
195 * \param[in] ul_channel Channel to configure
196 */
tc_stop(Tc * p_tc,uint32_t ul_channel)197 void tc_stop(
198 Tc *p_tc,
199 uint32_t ul_channel)
200 {
201 /* Validate inputs. */
202 Assert(p_tc);
203 Assert(ul_channel <
204 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
205
206 p_tc->TC_CHANNEL[ul_channel].TC_CCR = TC_CCR_CLKDIS;
207 }
208
209 /**
210 * \brief Read the counter value on the specified channel.
211 *
212 * \param[in] p_tc Module hardware register base address pointer
213 * \param[in] ul_channel Channel to read
214 *
215 * \return The counter value.
216 */
tc_read_cv(Tc * p_tc,uint32_t ul_channel)217 uint32_t tc_read_cv(
218 Tc *p_tc,
219 uint32_t ul_channel)
220 {
221 /* Validate inputs. */
222 Assert(p_tc);
223 Assert(ul_channel <
224 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
225
226 return p_tc->TC_CHANNEL[ul_channel].TC_CV;
227 }
228
229 /**
230 * \brief Read TC Register A (RA) on the specified channel.
231 *
232 * \param[in] p_tc Module hardware register base address pointer
233 * \param[in] ul_channel Channel to read
234 *
235 * \return The TC Register A (RA) value.
236 */
tc_read_ra(Tc * p_tc,uint32_t ul_channel)237 uint32_t tc_read_ra(
238 Tc *p_tc,
239 uint32_t ul_channel)
240 {
241 /* Validate inputs. */
242 Assert(p_tc);
243 Assert(ul_channel <
244 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
245
246 return p_tc->TC_CHANNEL[ul_channel].TC_RA;
247 }
248
249 /**
250 * \brief Read TC Register B (RB) on the specified channel.
251 *
252 * \param[in] p_tc Module hardware register base address pointer
253 * \param[in] ul_channel Channel to read
254 *
255 * \return The TC Register B (RB) value.
256 */
tc_read_rb(Tc * p_tc,uint32_t ul_channel)257 uint32_t tc_read_rb(
258 Tc *p_tc,
259 uint32_t ul_channel)
260 {
261 /* Validate inputs. */
262 Assert(p_tc);
263 Assert(ul_channel <
264 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
265
266 return p_tc->TC_CHANNEL[ul_channel].TC_RB;
267 }
268
269 /**
270 * \brief Read TC Register C (RC) on the specified channel.
271 *
272 * \param[in] p_tc Module hardware register base address pointer
273 * \param[in] ul_channel Channel to read
274 *
275 * \return The Register C (RC) value.
276 */
tc_read_rc(Tc * p_tc,uint32_t ul_channel)277 uint32_t tc_read_rc(
278 Tc *p_tc,
279 uint32_t ul_channel)
280 {
281 /* Validate inputs. */
282 Assert(p_tc);
283 Assert(ul_channel <
284 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
285
286 return p_tc->TC_CHANNEL[ul_channel].TC_RC;
287 }
288
289 /**
290 * \brief Write to TC Register A (RA) on the specified channel.
291 *
292 * \param[out] p_tc Module hardware register base address pointer
293 * \param[in] ul_channel Channel to write
294 * \param[in] ul_value Value to write
295 */
tc_write_ra(Tc * p_tc,uint32_t ul_channel,uint32_t ul_value)296 void tc_write_ra(
297 Tc *p_tc,
298 uint32_t ul_channel,
299 uint32_t ul_value)
300 {
301 /* Validate inputs. */
302 Assert(p_tc);
303 Assert(ul_channel <
304 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
305
306 p_tc->TC_CHANNEL[ul_channel].TC_RA = ul_value;
307 }
308
309 /**
310 * \brief Write to TC Register B (RB) on the specified channel.
311 *
312 * \param[out] p_tc Module hardware register base address pointer
313 * \param[in] ul_channel Channel to write
314 * \param[in] ul_value Value to write
315 */
tc_write_rb(Tc * p_tc,uint32_t ul_channel,uint32_t ul_value)316 void tc_write_rb(
317 Tc *p_tc,
318 uint32_t ul_channel,
319 uint32_t ul_value)
320 {
321 /* Validate inputs. */
322 Assert(p_tc);
323 Assert(ul_channel <
324 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
325
326 p_tc->TC_CHANNEL[ul_channel].TC_RB = ul_value;
327 }
328
329 /**
330 * \brief Write to TC Register C (RC) on the selected channel.
331 *
332 * \param[out] p_tc Module hardware register base address pointer
333 * \param[in] ul_channel Channel to write
334 * \param[in] ul_value Value to write
335 */
tc_write_rc(Tc * p_tc,uint32_t ul_channel,uint32_t ul_value)336 void tc_write_rc(
337 Tc *p_tc,
338 uint32_t ul_channel,
339 uint32_t ul_value)
340 {
341 /* Validate inputs. */
342 Assert(p_tc);
343 Assert(ul_channel <
344 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
345
346 p_tc->TC_CHANNEL[ul_channel].TC_RC = ul_value;
347 }
348
349 /**
350 * \brief Enable the TC interrupts on the specified channel.
351 *
352 * \param[in,out] p_tc Module hardware register base address pointer
353 * \param[in] ul_channel Channel to configure
354 * \param[in] ul_sources Bitmask of interrupt sources
355 *
356 * Where the input parameter <i>ul_sources</i> can be one or more of the following:
357 * <table>
358 * <tr>
359 * <th>Parameter Value</th>
360 * <th>Description</th>
361 * </tr>
362 * <tr><td>TC_IER_COVFS</td><td>Enables the Counter Overflow Interrupt</td></tr>
363 * <tr><td>TC_IER_LOVRS</td><td>Enables the Load Overrun Interrupt</td></tr>
364 * <tr><td>TC_IER_CPAS</td><td>Enables the RA Compare Interrupt</td></tr>
365 * <tr><td>TC_IER_CPBS</td><td>Enables the RB Compare Interrupt</td></tr>
366 * <tr><td>TC_IER_CPCS</td><td>Enables the RC Compare Interrupt</td></tr>
367 * <tr><td>TC_IER_LDRAS</td><td>Enables the RA Load Interrupt</td></tr>
368 * <tr><td>TC_IER_LDRBS</td><td>Enables the RB Load Interrupt</td></tr>
369 * <tr><td>TC_IER_ETRGS</td><td>Enables the External Trigger Interrupt</td></tr>
370 * </table>
371 */
tc_enable_interrupt(Tc * p_tc,uint32_t ul_channel,uint32_t ul_sources)372 void tc_enable_interrupt(
373 Tc *p_tc,
374 uint32_t ul_channel,
375 uint32_t ul_sources)
376 {
377 TcChannel *tc_channel;
378
379 /* Validate inputs. */
380 Assert(p_tc);
381 Assert(ul_channel <
382 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
383 tc_channel = p_tc->TC_CHANNEL + ul_channel;
384 tc_channel->TC_IER = ul_sources;
385 }
386
387 /**
388 * \brief Disable TC interrupts on the specified channel.
389 *
390 * \param[in,out] p_tc Module hardware register base address pointer
391 * \param[in] ul_channel Channel to configure
392 * \param[in] ul_sources A bitmask of Interrupt sources
393 *
394 * Where the input parameter <i>ul_sources</i> can be one or more of the following:
395 * <table>
396 * <tr>
397 * <th>Parameter Value</th>
398 * <th>Description</th>
399 * </tr>
400 * <tr><td>TC_IDR_COVFS</td><td>Disables the Counter Overflow Interrupt</td></tr>
401 * <tr><td>TC_IDR_LOVRS</td><td>Disables the Load Overrun Interrupt</td></tr>
402 * <tr><td>TC_IDR_CPAS</td><td>Disables the RA Compare Interrupt</td></tr>
403 * <tr><td>TC_IDR_CPBS</td><td>Disables the RB Compare Interrupt</td></tr>
404 * <tr><td>TC_IDR_CPCS</td><td>Disables the RC Compare Interrupt</td></tr>
405 * <tr><td>TC_IDR_LDRAS</td><td>Disables the RA Load Interrupt</td></tr>
406 * <tr><td>TC_IDR_LDRBS</td><td>Disables the RB Load Interrupt</td></tr>
407 * <tr><td>TC_IDR_ETRGS</td><td>Disables the External Trigger Interrupt</td></tr>
408 * </table>
409 */
tc_disable_interrupt(Tc * p_tc,uint32_t ul_channel,uint32_t ul_sources)410 void tc_disable_interrupt(
411 Tc *p_tc,
412 uint32_t ul_channel,
413 uint32_t ul_sources)
414 {
415 TcChannel *tc_channel;
416
417 /* Validate inputs. */
418 Assert(p_tc);
419 Assert(ul_channel <
420 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
421 tc_channel = p_tc->TC_CHANNEL + ul_channel;
422 tc_channel->TC_IDR = ul_sources;
423 }
424
425 /**
426 * \brief Read the TC interrupt mask for the specified channel.
427 *
428 * \param[in] p_tc Module hardware register base address pointer
429 * \param[in] ul_channel Channel to read
430 *
431 * \return The TC interrupt mask value.
432 */
tc_get_interrupt_mask(Tc * p_tc,uint32_t ul_channel)433 uint32_t tc_get_interrupt_mask(
434 Tc *p_tc,
435 uint32_t ul_channel)
436 {
437 TcChannel *tc_channel;
438
439 /* Validate inputs. */
440 Assert(p_tc);
441 Assert(ul_channel <
442 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
443 tc_channel = p_tc->TC_CHANNEL + ul_channel;
444 return tc_channel->TC_IMR;
445 }
446
447 /**
448 * \brief Get the current status for the specified TC channel.
449 *
450 * \param[in] p_tc Module hardware register base address pointer
451 * \param[in] ul_channel Channel number
452 *
453 * \return The current TC status.
454 */
tc_get_status(Tc * p_tc,uint32_t ul_channel)455 uint32_t tc_get_status(
456 Tc *p_tc,
457 uint32_t ul_channel)
458 {
459 TcChannel *tc_channel;
460
461 /* Validate inputs. */
462 Assert(p_tc);
463 Assert(ul_channel <
464 (sizeof(p_tc->TC_CHANNEL) / sizeof(p_tc->TC_CHANNEL[0])));
465
466 tc_channel = p_tc->TC_CHANNEL + ul_channel;
467 return tc_channel->TC_SR;
468 }
469
470 /* TC divisor used to find the lowest acceptable timer frequency */
471 #define TC_DIV_FACTOR 65536
472
473 #if (!SAM4L) && !defined(__DOXYGEN__)
474
475 #ifndef FREQ_SLOW_CLOCK_EXT
476 #define FREQ_SLOW_CLOCK_EXT 32768 /* External slow clock frequency (hz) */
477 #endif
478
479 /**
480 * \brief Find the best MCK divisor.
481 *
482 * Finds the best MCK divisor given the timer frequency and MCK. The result
483 * is guaranteed to satisfy the following equation:
484 * \code (MCK / (DIV * 65536)) <= freq <= (MCK / DIV) \endcode
485 * With DIV being the lowest possible value, to maximize timing adjust resolution.
486 *
487 * \param[in] ul_freq Desired timer frequency
488 * \param[in] ul_mck Master clock frequency
489 * \param[out] p_uldiv Divisor value
490 * \param[out] p_ultcclks TCCLKS field value for divisor
491 * \param[in] ul_boardmck Board clock frequency
492 *
493 * \return The divisor found status.
494 * \retval 0 No suitable divisor was found
495 * \retval 1 A divisor was found
496 */
tc_find_mck_divisor(uint32_t ul_freq,uint32_t ul_mck,uint32_t * p_uldiv,uint32_t * p_ultcclks,uint32_t ul_boardmck)497 uint32_t tc_find_mck_divisor(
498 uint32_t ul_freq,
499 uint32_t ul_mck,
500 uint32_t *p_uldiv,
501 uint32_t *p_ultcclks,
502 uint32_t ul_boardmck)
503 {
504 const uint32_t divisors[5] = { 2, 8, 32, 128,
505 ul_boardmck / FREQ_SLOW_CLOCK_EXT };
506 uint32_t ul_index;
507 uint32_t ul_high, ul_low;
508
509 /* Satisfy frequency bound. */
510 for (ul_index = 0;
511 ul_index < (sizeof(divisors) / sizeof(divisors[0]));
512 ul_index++) {
513 ul_high = ul_mck / divisors[ul_index];
514 ul_low = ul_high / TC_DIV_FACTOR;
515 if (ul_freq > ul_high) {
516 return 0;
517 } else if (ul_freq >= ul_low) {
518 break;
519 }
520 }
521 if (ul_index >= (sizeof(divisors) / sizeof(divisors[0]))) {
522 return 0;
523 }
524
525 /* Store results. */
526 if (p_uldiv) {
527 *p_uldiv = divisors[ul_index];
528 }
529
530 if (p_ultcclks) {
531 *p_ultcclks = ul_index;
532 }
533
534 return 1;
535 }
536
537 #endif /* (!SAM4L) */
538
539 #if (SAM4L) || defined(__DOXYGEN__)
540 /**
541 * \brief Find the best PBA/MCK divisor.
542 *
543 * <b>For SAM4L devices:</b> Finds the best PBA divisor given the timer
544 * frequency and PBA clock. The result is guaranteed to satisfy the following equation:
545 * \code (ul_pbaclk / (2* DIV * 65536)) <= freq <= (ul_pbaclk / (2* DIV)) \endcode
546 * with DIV being the lowest possible value, to maximize timing adjust resolution.
547 *
548 * <b>For non SAM4L devices:</b> Finds the best MCK divisor given the timer frequency
549 * and MCK. The result is guaranteed to satisfy the following equation:
550 * \code (MCK / (DIV * 65536)) <= freq <= (MCK / DIV) \endcode
551 * with DIV being the lowest possible value, to maximize timing adjust resolution.
552 *
553 * \param[in] ul_freq Desired timer frequency
554 * \param[in] ul_mck PBA clock frequency
555 * \param[out] p_uldiv Divisor value
556 * \param[out] p_ultcclks TCCLKS field value for divisor
557 * \param[in] ul_boardmck Board clock frequency (set to 0 for SAM4L devices)
558 *
559 * \return The divisor found status.
560 * \retval 0 No suitable divisor was found
561 * \retval 1 A divisor was found
562 */
tc_find_mck_divisor(uint32_t ul_freq,uint32_t ul_mck,uint32_t * p_uldiv,uint32_t * p_ultcclks,uint32_t ul_boardmck)563 uint32_t tc_find_mck_divisor(
564 uint32_t ul_freq,
565 uint32_t ul_mck,
566 uint32_t *p_uldiv,
567 uint32_t *p_ultcclks,
568 uint32_t ul_boardmck)
569 {
570 const uint32_t divisors[5] = { 0, 2, 8, 32, 128};
571 uint32_t ul_index;
572 uint32_t ul_high, ul_low;
573
574 UNUSED(ul_boardmck);
575
576 /* Satisfy frequency bound. */
577 for (ul_index = 1;
578 ul_index < (sizeof(divisors) / sizeof(divisors[0]));
579 ul_index++) {
580 ul_high = ul_mck / divisors[ul_index];
581 ul_low = ul_high / TC_DIV_FACTOR;
582 if (ul_freq > ul_high) {
583 return 0;
584 } else if (ul_freq >= ul_low) {
585 break;
586 }
587 }
588 if (ul_index >= (sizeof(divisors) / sizeof(divisors[0]))) {
589 return 0;
590 }
591
592 /* Store results. */
593 if (p_uldiv) {
594 *p_uldiv = divisors[ul_index];
595 }
596
597 if (p_ultcclks) {
598 *p_ultcclks = ul_index;
599 }
600
601 return 1;
602 }
603
604 #endif /* (SAM4L) || defined(__DOXYGEN__) */
605
606 #if (!SAM4L && !SAMG) || defined(__DOXYGEN__)
607
608 /**
609 * \brief Enable TC QDEC interrupts.
610 *
611 * \note This function is not available on SAM4L or SAMG devices.
612 *
613 * \param[out] p_tc Module hardware register base address pointer
614 * \param[in] ul_sources A bitmask of QDEC interrupts to be enabled
615 *
616 * Where the input parameter <i>ul_sources</i> can be one or more of the following:
617 * <table>
618 * <tr>
619 * <th>Parameter Value</th>
620 * <th>Description</th>
621 * </tr>
622 * <tr><td>TC_QIER_IDX</td><td>Enable the rising edge detected on IDX input interrupt</td></tr>
623 * <tr><td>TC_QIER_DIRCHG</td><td>Enable the change in rotation direction detected interrupt</td></tr>
624 * <tr><td>TC_QIER_QERR</td><td>Enable the quadrature error detected on PHA/PHB interrupt</td></tr>
625 * </table>
626 */
tc_enable_qdec_interrupt(Tc * p_tc,uint32_t ul_sources)627 void tc_enable_qdec_interrupt(
628 Tc *p_tc,
629 uint32_t ul_sources)
630 {
631 /* Validate inputs. */
632 Assert(p_tc);
633
634 p_tc->TC_QIER = ul_sources;
635 }
636
637 /**
638 * \brief Disable TC QDEC interrupts.
639 *
640 * \note This function is not available on SAM4L or SAMG devices.
641 *
642 * \param[out] p_tc Module hardware register base address pointer
643 * \param[in] ul_sources A bitmask of QDEC interrupts to be disabled
644 *
645 * Where the input parameter <i>ul_sources</i> can be one or more of the following:
646 * <table>
647 * <tr>
648 * <th>Parameter Value</th>
649 * <th>Description</th>
650 * </tr>
651 * <tr><td>TC_QIDR_IDX</td><td>Disable the rising edge detected on IDX input interrupt</td></tr>
652 * <tr><td>TC_QIDR_DIRCHG</td><td>Disable the change in rotation direction detected interrupt</td></tr>
653 * <tr><td>TC_QIDR_QERR</td><td>Disable the quadrature error detected on PHA/PHB interrupt</td></tr>
654 * </table>
655 */
tc_disable_qdec_interrupt(Tc * p_tc,uint32_t ul_sources)656 void tc_disable_qdec_interrupt(
657 Tc *p_tc,
658 uint32_t ul_sources)
659 {
660 /* Validate inputs. */
661 Assert(p_tc);
662
663 p_tc->TC_QIDR = ul_sources;
664 }
665
666 /**
667 * \brief Read TC QDEC interrupt mask.
668 *
669 * \note This function is not available on SAM4L or SAMG devices.
670 *
671 * \param[in] p_tc Module hardware register base address pointer
672 *
673 * \return The QDEC interrupt mask value.
674 */
tc_get_qdec_interrupt_mask(Tc * p_tc)675 uint32_t tc_get_qdec_interrupt_mask(
676 Tc *p_tc)
677 {
678 /* Validate inputs. */
679 Assert(p_tc);
680
681 return p_tc->TC_QIMR;
682 }
683
684 /**
685 * \brief Get current TC QDEC interrupt status.
686 *
687 * \note This function is not available on SAM4L or SAMG devices.
688 *
689 * \param[in] p_tc Module hardware register base address pointer
690 *
691 * \return The TC QDEC interrupt status.
692 */
tc_get_qdec_interrupt_status(Tc * p_tc)693 uint32_t tc_get_qdec_interrupt_status(
694 Tc *p_tc)
695 {
696 /* Validate inputs. */
697 Assert(p_tc);
698
699 return p_tc->TC_QISR;
700 }
701
702 #endif /* (!SAM4L && !SAMG) || defined(__DOXYGEN__) */
703
704 #if (!SAM3U) || defined(__DOXYGEN__)
705
706 /**
707 * \brief Enable or disable write protection of TC registers.
708 *
709 * \note This function is not available on SAM3U devices.
710 *
711 * \param[out] p_tc Module hardware register base address pointer
712 * \param[in] ul_enable 1 to enable, 0 to disable
713 */
tc_set_writeprotect(Tc * p_tc,uint32_t ul_enable)714 void tc_set_writeprotect(
715 Tc *p_tc,
716 uint32_t ul_enable)
717 {
718 /* Validate inputs. */
719 Assert(p_tc);
720
721 if (ul_enable) {
722 p_tc->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN;
723 } else {
724 p_tc->TC_WPMR = TC_WPMR_WPKEY_PASSWD;
725 }
726 }
727
728 #endif /* (!SAM3U) || defined(__DOXYGEN__) */
729
730 #if SAM4L || defined(__DOXYGEN__)
731
732 /**
733 * \brief Indicate TC features.
734 *
735 * \note This function is only available on SAM4L devices.
736 *
737 * \param[in] p_tc Module hardware register base address pointer
738 *
739 * \return The TC FEATURES register contents.
740 */
tc_get_feature(Tc * p_tc)741 uint32_t tc_get_feature(
742 Tc *p_tc)
743 {
744 /* Validate inputs. */
745 Assert(p_tc);
746
747 return p_tc->TC_FEATURES;
748 }
749
750 /**
751 * \brief Indicate TC version.
752 *
753 * \note This function is only available on SAM4L devices.
754 *
755 * \param[in] p_tc Module hardware register base address pointer
756 *
757 * \return The TC VERSION register contents.
758 */
tc_get_version(Tc * p_tc)759 uint32_t tc_get_version(
760 Tc *p_tc)
761 {
762 /* Validate inputs. */
763 Assert(p_tc);
764
765 return p_tc->TC_VERSION;
766 }
767
768 #endif /* SAM4L || defined(__DOXYGEN__) */
769
770 /// @cond
771 /**INDENT-OFF**/
772 #ifdef __cplusplus
773 }
774 #endif
775 /**INDENT-ON**/
776 /// @endcond
777