xref: /btstack/port/samv71-xplained-atwilc3000/ASF/sam/drivers/tc/tc.c (revision 1b2596b5303dd8caeea8565532c93cca8dab8cc4)
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